aframe-extras.controls.js 513 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994
  1. (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  2. require('./src/controls').registerAll();
  3. },{"./src/controls":78}],2:[function(require,module,exports){
  4. module.exports = Object.assign(function GamepadButton () {}, {
  5. FACE_1: 0,
  6. FACE_2: 1,
  7. FACE_3: 2,
  8. FACE_4: 3,
  9. L_SHOULDER_1: 4,
  10. R_SHOULDER_1: 5,
  11. L_SHOULDER_2: 6,
  12. R_SHOULDER_2: 7,
  13. SELECT: 8,
  14. START: 9,
  15. DPAD_UP: 12,
  16. DPAD_DOWN: 13,
  17. DPAD_LEFT: 14,
  18. DPAD_RIGHT: 15,
  19. VENDOR: 16,
  20. });
  21. },{}],3:[function(require,module,exports){
  22. function GamepadButtonEvent (type, index, details) {
  23. this.type = type;
  24. this.index = index;
  25. this.pressed = details.pressed;
  26. this.value = details.value;
  27. }
  28. module.exports = GamepadButtonEvent;
  29. },{}],4:[function(require,module,exports){
  30. /**
  31. * Polyfill for the additional KeyboardEvent properties defined in the D3E and
  32. * D4E draft specifications, by @inexorabletash.
  33. *
  34. * See: https://github.com/inexorabletash/polyfill
  35. */
  36. (function(global) {
  37. var nativeKeyboardEvent = ('KeyboardEvent' in global);
  38. if (!nativeKeyboardEvent)
  39. global.KeyboardEvent = function KeyboardEvent() { throw TypeError('Illegal constructor'); };
  40. global.KeyboardEvent.DOM_KEY_LOCATION_STANDARD = 0x00; // Default or unknown location
  41. global.KeyboardEvent.DOM_KEY_LOCATION_LEFT = 0x01; // e.g. Left Alt key
  42. global.KeyboardEvent.DOM_KEY_LOCATION_RIGHT = 0x02; // e.g. Right Alt key
  43. global.KeyboardEvent.DOM_KEY_LOCATION_NUMPAD = 0x03; // e.g. Numpad 0 or +
  44. var STANDARD = window.KeyboardEvent.DOM_KEY_LOCATION_STANDARD,
  45. LEFT = window.KeyboardEvent.DOM_KEY_LOCATION_LEFT,
  46. RIGHT = window.KeyboardEvent.DOM_KEY_LOCATION_RIGHT,
  47. NUMPAD = window.KeyboardEvent.DOM_KEY_LOCATION_NUMPAD;
  48. //--------------------------------------------------------------------
  49. //
  50. // Utilities
  51. //
  52. //--------------------------------------------------------------------
  53. function contains(s, ss) { return String(s).indexOf(ss) !== -1; }
  54. var os = (function() {
  55. if (contains(navigator.platform, 'Win')) { return 'win'; }
  56. if (contains(navigator.platform, 'Mac')) { return 'mac'; }
  57. if (contains(navigator.platform, 'CrOS')) { return 'cros'; }
  58. if (contains(navigator.platform, 'Linux')) { return 'linux'; }
  59. if (contains(navigator.userAgent, 'iPad') || contains(navigator.platform, 'iPod') || contains(navigator.platform, 'iPhone')) { return 'ios'; }
  60. return '';
  61. } ());
  62. var browser = (function() {
  63. if (contains(navigator.userAgent, 'Chrome/')) { return 'chrome'; }
  64. if (contains(navigator.vendor, 'Apple')) { return 'safari'; }
  65. if (contains(navigator.userAgent, 'MSIE')) { return 'ie'; }
  66. if (contains(navigator.userAgent, 'Gecko/')) { return 'moz'; }
  67. if (contains(navigator.userAgent, 'Opera/')) { return 'opera'; }
  68. return '';
  69. } ());
  70. var browser_os = browser + '-' + os;
  71. function mergeIf(baseTable, select, table) {
  72. if (browser_os === select || browser === select || os === select) {
  73. Object.keys(table).forEach(function(keyCode) {
  74. baseTable[keyCode] = table[keyCode];
  75. });
  76. }
  77. }
  78. function remap(o, key) {
  79. var r = {};
  80. Object.keys(o).forEach(function(k) {
  81. var item = o[k];
  82. if (key in item) {
  83. r[item[key]] = item;
  84. }
  85. });
  86. return r;
  87. }
  88. function invert(o) {
  89. var r = {};
  90. Object.keys(o).forEach(function(k) {
  91. r[o[k]] = k;
  92. });
  93. return r;
  94. }
  95. //--------------------------------------------------------------------
  96. //
  97. // Generic Mappings
  98. //
  99. //--------------------------------------------------------------------
  100. // "keyInfo" is a dictionary:
  101. // code: string - name from DOM Level 3 KeyboardEvent code Values
  102. // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3Events-code.html
  103. // location (optional): number - one of the DOM_KEY_LOCATION values
  104. // keyCap (optional): string - keyboard label in en-US locale
  105. // USB code Usage ID from page 0x07 unless otherwise noted (Informative)
  106. // Map of keyCode to keyInfo
  107. var keyCodeToInfoTable = {
  108. // 0x01 - VK_LBUTTON
  109. // 0x02 - VK_RBUTTON
  110. 0x03: { code: 'Cancel' }, // [USB: 0x9b] char \x0018 ??? (Not in D3E)
  111. // 0x04 - VK_MBUTTON
  112. // 0x05 - VK_XBUTTON1
  113. // 0x06 - VK_XBUTTON2
  114. 0x06: { code: 'Help' }, // [USB: 0x75] ???
  115. // 0x07 - undefined
  116. 0x08: { code: 'Backspace' }, // [USB: 0x2a] Labelled Delete on Macintosh keyboards.
  117. 0x09: { code: 'Tab' }, // [USB: 0x2b]
  118. // 0x0A-0x0B - reserved
  119. 0X0C: { code: 'Clear' }, // [USB: 0x9c] NumPad Center (Not in D3E)
  120. 0X0D: { code: 'Enter' }, // [USB: 0x28]
  121. // 0x0E-0x0F - undefined
  122. 0x10: { code: 'Shift' },
  123. 0x11: { code: 'Control' },
  124. 0x12: { code: 'Alt' },
  125. 0x13: { code: 'Pause' }, // [USB: 0x48]
  126. 0x14: { code: 'CapsLock' }, // [USB: 0x39]
  127. 0x15: { code: 'KanaMode' }, // [USB: 0x88] - "HangulMode" for Korean layout
  128. 0x16: { code: 'HangulMode' }, // [USB: 0x90] 0x15 as well in MSDN VK table ???
  129. 0x17: { code: 'JunjaMode' }, // (Not in D3E)
  130. 0x18: { code: 'FinalMode' }, // (Not in D3E)
  131. 0x19: { code: 'KanjiMode' }, // [USB: 0x91] - "HanjaMode" for Korean layout
  132. // 0x1A - undefined
  133. 0x1B: { code: 'Escape' }, // [USB: 0x29]
  134. 0x1C: { code: 'Convert' }, // [USB: 0x8a]
  135. 0x1D: { code: 'NonConvert' }, // [USB: 0x8b]
  136. 0x1E: { code: 'Accept' }, // (Not in D3E)
  137. 0x1F: { code: 'ModeChange' }, // (Not in D3E)
  138. 0x20: { code: 'Space' }, // [USB: 0x2c]
  139. 0x21: { code: 'PageUp' }, // [USB: 0x4b]
  140. 0x22: { code: 'PageDown' }, // [USB: 0x4e]
  141. 0x23: { code: 'End' }, // [USB: 0x4d]
  142. 0x24: { code: 'Home' }, // [USB: 0x4a]
  143. 0x25: { code: 'ArrowLeft' }, // [USB: 0x50]
  144. 0x26: { code: 'ArrowUp' }, // [USB: 0x52]
  145. 0x27: { code: 'ArrowRight' }, // [USB: 0x4f]
  146. 0x28: { code: 'ArrowDown' }, // [USB: 0x51]
  147. 0x29: { code: 'Select' }, // (Not in D3E)
  148. 0x2A: { code: 'Print' }, // (Not in D3E)
  149. 0x2B: { code: 'Execute' }, // [USB: 0x74] (Not in D3E)
  150. 0x2C: { code: 'PrintScreen' }, // [USB: 0x46]
  151. 0x2D: { code: 'Insert' }, // [USB: 0x49]
  152. 0x2E: { code: 'Delete' }, // [USB: 0x4c]
  153. 0x2F: { code: 'Help' }, // [USB: 0x75] ???
  154. 0x30: { code: 'Digit0', keyCap: '0' }, // [USB: 0x27] 0)
  155. 0x31: { code: 'Digit1', keyCap: '1' }, // [USB: 0x1e] 1!
  156. 0x32: { code: 'Digit2', keyCap: '2' }, // [USB: 0x1f] 2@
  157. 0x33: { code: 'Digit3', keyCap: '3' }, // [USB: 0x20] 3#
  158. 0x34: { code: 'Digit4', keyCap: '4' }, // [USB: 0x21] 4$
  159. 0x35: { code: 'Digit5', keyCap: '5' }, // [USB: 0x22] 5%
  160. 0x36: { code: 'Digit6', keyCap: '6' }, // [USB: 0x23] 6^
  161. 0x37: { code: 'Digit7', keyCap: '7' }, // [USB: 0x24] 7&
  162. 0x38: { code: 'Digit8', keyCap: '8' }, // [USB: 0x25] 8*
  163. 0x39: { code: 'Digit9', keyCap: '9' }, // [USB: 0x26] 9(
  164. // 0x3A-0x40 - undefined
  165. 0x41: { code: 'KeyA', keyCap: 'a' }, // [USB: 0x04]
  166. 0x42: { code: 'KeyB', keyCap: 'b' }, // [USB: 0x05]
  167. 0x43: { code: 'KeyC', keyCap: 'c' }, // [USB: 0x06]
  168. 0x44: { code: 'KeyD', keyCap: 'd' }, // [USB: 0x07]
  169. 0x45: { code: 'KeyE', keyCap: 'e' }, // [USB: 0x08]
  170. 0x46: { code: 'KeyF', keyCap: 'f' }, // [USB: 0x09]
  171. 0x47: { code: 'KeyG', keyCap: 'g' }, // [USB: 0x0a]
  172. 0x48: { code: 'KeyH', keyCap: 'h' }, // [USB: 0x0b]
  173. 0x49: { code: 'KeyI', keyCap: 'i' }, // [USB: 0x0c]
  174. 0x4A: { code: 'KeyJ', keyCap: 'j' }, // [USB: 0x0d]
  175. 0x4B: { code: 'KeyK', keyCap: 'k' }, // [USB: 0x0e]
  176. 0x4C: { code: 'KeyL', keyCap: 'l' }, // [USB: 0x0f]
  177. 0x4D: { code: 'KeyM', keyCap: 'm' }, // [USB: 0x10]
  178. 0x4E: { code: 'KeyN', keyCap: 'n' }, // [USB: 0x11]
  179. 0x4F: { code: 'KeyO', keyCap: 'o' }, // [USB: 0x12]
  180. 0x50: { code: 'KeyP', keyCap: 'p' }, // [USB: 0x13]
  181. 0x51: { code: 'KeyQ', keyCap: 'q' }, // [USB: 0x14]
  182. 0x52: { code: 'KeyR', keyCap: 'r' }, // [USB: 0x15]
  183. 0x53: { code: 'KeyS', keyCap: 's' }, // [USB: 0x16]
  184. 0x54: { code: 'KeyT', keyCap: 't' }, // [USB: 0x17]
  185. 0x55: { code: 'KeyU', keyCap: 'u' }, // [USB: 0x18]
  186. 0x56: { code: 'KeyV', keyCap: 'v' }, // [USB: 0x19]
  187. 0x57: { code: 'KeyW', keyCap: 'w' }, // [USB: 0x1a]
  188. 0x58: { code: 'KeyX', keyCap: 'x' }, // [USB: 0x1b]
  189. 0x59: { code: 'KeyY', keyCap: 'y' }, // [USB: 0x1c]
  190. 0x5A: { code: 'KeyZ', keyCap: 'z' }, // [USB: 0x1d]
  191. 0x5B: { code: 'OSLeft', location: LEFT }, // [USB: 0xe3]
  192. 0x5C: { code: 'OSRight', location: RIGHT }, // [USB: 0xe7]
  193. 0x5D: { code: 'ContextMenu' }, // [USB: 0x65] Context Menu
  194. // 0x5E - reserved
  195. 0x5F: { code: 'Standby' }, // [USB: 0x82] Sleep
  196. 0x60: { code: 'Numpad0', keyCap: '0', location: NUMPAD }, // [USB: 0x62]
  197. 0x61: { code: 'Numpad1', keyCap: '1', location: NUMPAD }, // [USB: 0x59]
  198. 0x62: { code: 'Numpad2', keyCap: '2', location: NUMPAD }, // [USB: 0x5a]
  199. 0x63: { code: 'Numpad3', keyCap: '3', location: NUMPAD }, // [USB: 0x5b]
  200. 0x64: { code: 'Numpad4', keyCap: '4', location: NUMPAD }, // [USB: 0x5c]
  201. 0x65: { code: 'Numpad5', keyCap: '5', location: NUMPAD }, // [USB: 0x5d]
  202. 0x66: { code: 'Numpad6', keyCap: '6', location: NUMPAD }, // [USB: 0x5e]
  203. 0x67: { code: 'Numpad7', keyCap: '7', location: NUMPAD }, // [USB: 0x5f]
  204. 0x68: { code: 'Numpad8', keyCap: '8', location: NUMPAD }, // [USB: 0x60]
  205. 0x69: { code: 'Numpad9', keyCap: '9', location: NUMPAD }, // [USB: 0x61]
  206. 0x6A: { code: 'NumpadMultiply', keyCap: '*', location: NUMPAD }, // [USB: 0x55]
  207. 0x6B: { code: 'NumpadAdd', keyCap: '+', location: NUMPAD }, // [USB: 0x57]
  208. 0x6C: { code: 'NumpadComma', keyCap: ',', location: NUMPAD }, // [USB: 0x85]
  209. 0x6D: { code: 'NumpadSubtract', keyCap: '-', location: NUMPAD }, // [USB: 0x56]
  210. 0x6E: { code: 'NumpadDecimal', keyCap: '.', location: NUMPAD }, // [USB: 0x63]
  211. 0x6F: { code: 'NumpadDivide', keyCap: '/', location: NUMPAD }, // [USB: 0x54]
  212. 0x70: { code: 'F1' }, // [USB: 0x3a]
  213. 0x71: { code: 'F2' }, // [USB: 0x3b]
  214. 0x72: { code: 'F3' }, // [USB: 0x3c]
  215. 0x73: { code: 'F4' }, // [USB: 0x3d]
  216. 0x74: { code: 'F5' }, // [USB: 0x3e]
  217. 0x75: { code: 'F6' }, // [USB: 0x3f]
  218. 0x76: { code: 'F7' }, // [USB: 0x40]
  219. 0x77: { code: 'F8' }, // [USB: 0x41]
  220. 0x78: { code: 'F9' }, // [USB: 0x42]
  221. 0x79: { code: 'F10' }, // [USB: 0x43]
  222. 0x7A: { code: 'F11' }, // [USB: 0x44]
  223. 0x7B: { code: 'F12' }, // [USB: 0x45]
  224. 0x7C: { code: 'F13' }, // [USB: 0x68]
  225. 0x7D: { code: 'F14' }, // [USB: 0x69]
  226. 0x7E: { code: 'F15' }, // [USB: 0x6a]
  227. 0x7F: { code: 'F16' }, // [USB: 0x6b]
  228. 0x80: { code: 'F17' }, // [USB: 0x6c]
  229. 0x81: { code: 'F18' }, // [USB: 0x6d]
  230. 0x82: { code: 'F19' }, // [USB: 0x6e]
  231. 0x83: { code: 'F20' }, // [USB: 0x6f]
  232. 0x84: { code: 'F21' }, // [USB: 0x70]
  233. 0x85: { code: 'F22' }, // [USB: 0x71]
  234. 0x86: { code: 'F23' }, // [USB: 0x72]
  235. 0x87: { code: 'F24' }, // [USB: 0x73]
  236. // 0x88-0x8F - unassigned
  237. 0x90: { code: 'NumLock', location: NUMPAD }, // [USB: 0x53]
  238. 0x91: { code: 'ScrollLock' }, // [USB: 0x47]
  239. // 0x92-0x96 - OEM specific
  240. // 0x97-0x9F - unassigned
  241. // NOTE: 0xA0-0xA5 usually mapped to 0x10-0x12 in browsers
  242. 0xA0: { code: 'ShiftLeft', location: LEFT }, // [USB: 0xe1]
  243. 0xA1: { code: 'ShiftRight', location: RIGHT }, // [USB: 0xe5]
  244. 0xA2: { code: 'ControlLeft', location: LEFT }, // [USB: 0xe0]
  245. 0xA3: { code: 'ControlRight', location: RIGHT }, // [USB: 0xe4]
  246. 0xA4: { code: 'AltLeft', location: LEFT }, // [USB: 0xe2]
  247. 0xA5: { code: 'AltRight', location: RIGHT }, // [USB: 0xe6]
  248. 0xA6: { code: 'BrowserBack' }, // [USB: 0x0c/0x0224]
  249. 0xA7: { code: 'BrowserForward' }, // [USB: 0x0c/0x0225]
  250. 0xA8: { code: 'BrowserRefresh' }, // [USB: 0x0c/0x0227]
  251. 0xA9: { code: 'BrowserStop' }, // [USB: 0x0c/0x0226]
  252. 0xAA: { code: 'BrowserSearch' }, // [USB: 0x0c/0x0221]
  253. 0xAB: { code: 'BrowserFavorites' }, // [USB: 0x0c/0x0228]
  254. 0xAC: { code: 'BrowserHome' }, // [USB: 0x0c/0x0222]
  255. 0xAD: { code: 'VolumeMute' }, // [USB: 0x7f]
  256. 0xAE: { code: 'VolumeDown' }, // [USB: 0x81]
  257. 0xAF: { code: 'VolumeUp' }, // [USB: 0x80]
  258. 0xB0: { code: 'MediaTrackNext' }, // [USB: 0x0c/0x00b5]
  259. 0xB1: { code: 'MediaTrackPrevious' }, // [USB: 0x0c/0x00b6]
  260. 0xB2: { code: 'MediaStop' }, // [USB: 0x0c/0x00b7]
  261. 0xB3: { code: 'MediaPlayPause' }, // [USB: 0x0c/0x00cd]
  262. 0xB4: { code: 'LaunchMail' }, // [USB: 0x0c/0x018a]
  263. 0xB5: { code: 'MediaSelect' },
  264. 0xB6: { code: 'LaunchApp1' },
  265. 0xB7: { code: 'LaunchApp2' },
  266. // 0xB8-0xB9 - reserved
  267. 0xBA: { code: 'Semicolon', keyCap: ';' }, // [USB: 0x33] ;: (US Standard 101)
  268. 0xBB: { code: 'Equal', keyCap: '=' }, // [USB: 0x2e] =+
  269. 0xBC: { code: 'Comma', keyCap: ',' }, // [USB: 0x36] ,<
  270. 0xBD: { code: 'Minus', keyCap: '-' }, // [USB: 0x2d] -_
  271. 0xBE: { code: 'Period', keyCap: '.' }, // [USB: 0x37] .>
  272. 0xBF: { code: 'Slash', keyCap: '/' }, // [USB: 0x38] /? (US Standard 101)
  273. 0xC0: { code: 'Backquote', keyCap: '`' }, // [USB: 0x35] `~ (US Standard 101)
  274. // 0xC1-0xCF - reserved
  275. // 0xD0-0xD7 - reserved
  276. // 0xD8-0xDA - unassigned
  277. 0xDB: { code: 'BracketLeft', keyCap: '[' }, // [USB: 0x2f] [{ (US Standard 101)
  278. 0xDC: { code: 'Backslash', keyCap: '\\' }, // [USB: 0x31] \| (US Standard 101)
  279. 0xDD: { code: 'BracketRight', keyCap: ']' }, // [USB: 0x30] ]} (US Standard 101)
  280. 0xDE: { code: 'Quote', keyCap: '\'' }, // [USB: 0x34] '" (US Standard 101)
  281. // 0xDF - miscellaneous/varies
  282. // 0xE0 - reserved
  283. // 0xE1 - OEM specific
  284. 0xE2: { code: 'IntlBackslash', keyCap: '\\' }, // [USB: 0x64] \| (UK Standard 102)
  285. // 0xE3-0xE4 - OEM specific
  286. 0xE5: { code: 'Process' }, // (Not in D3E)
  287. // 0xE6 - OEM specific
  288. // 0xE7 - VK_PACKET
  289. // 0xE8 - unassigned
  290. // 0xE9-0xEF - OEM specific
  291. // 0xF0-0xF5 - OEM specific
  292. 0xF6: { code: 'Attn' }, // [USB: 0x9a] (Not in D3E)
  293. 0xF7: { code: 'CrSel' }, // [USB: 0xa3] (Not in D3E)
  294. 0xF8: { code: 'ExSel' }, // [USB: 0xa4] (Not in D3E)
  295. 0xF9: { code: 'EraseEof' }, // (Not in D3E)
  296. 0xFA: { code: 'Play' }, // (Not in D3E)
  297. 0xFB: { code: 'ZoomToggle' }, // (Not in D3E)
  298. // 0xFC - VK_NONAME - reserved
  299. // 0xFD - VK_PA1
  300. 0xFE: { code: 'Clear' } // [USB: 0x9c] (Not in D3E)
  301. };
  302. // No legacy keyCode, but listed in D3E:
  303. // code: usb
  304. // 'IntlHash': 0x070032,
  305. // 'IntlRo': 0x070087,
  306. // 'IntlYen': 0x070089,
  307. // 'NumpadBackspace': 0x0700bb,
  308. // 'NumpadClear': 0x0700d8,
  309. // 'NumpadClearEntry': 0x0700d9,
  310. // 'NumpadMemoryAdd': 0x0700d3,
  311. // 'NumpadMemoryClear': 0x0700d2,
  312. // 'NumpadMemoryRecall': 0x0700d1,
  313. // 'NumpadMemoryStore': 0x0700d0,
  314. // 'NumpadMemorySubtract': 0x0700d4,
  315. // 'NumpadParenLeft': 0x0700b6,
  316. // 'NumpadParenRight': 0x0700b7,
  317. //--------------------------------------------------------------------
  318. //
  319. // Browser/OS Specific Mappings
  320. //
  321. //--------------------------------------------------------------------
  322. mergeIf(keyCodeToInfoTable,
  323. 'moz', {
  324. 0x3B: { code: 'Semicolon', keyCap: ';' }, // [USB: 0x33] ;: (US Standard 101)
  325. 0x3D: { code: 'Equal', keyCap: '=' }, // [USB: 0x2e] =+
  326. 0x6B: { code: 'Equal', keyCap: '=' }, // [USB: 0x2e] =+
  327. 0x6D: { code: 'Minus', keyCap: '-' }, // [USB: 0x2d] -_
  328. 0xBB: { code: 'NumpadAdd', keyCap: '+', location: NUMPAD }, // [USB: 0x57]
  329. 0xBD: { code: 'NumpadSubtract', keyCap: '-', location: NUMPAD } // [USB: 0x56]
  330. });
  331. mergeIf(keyCodeToInfoTable,
  332. 'moz-mac', {
  333. 0x0C: { code: 'NumLock', location: NUMPAD }, // [USB: 0x53]
  334. 0xAD: { code: 'Minus', keyCap: '-' } // [USB: 0x2d] -_
  335. });
  336. mergeIf(keyCodeToInfoTable,
  337. 'moz-win', {
  338. 0xAD: { code: 'Minus', keyCap: '-' } // [USB: 0x2d] -_
  339. });
  340. mergeIf(keyCodeToInfoTable,
  341. 'chrome-mac', {
  342. 0x5D: { code: 'OSRight', location: RIGHT } // [USB: 0xe7]
  343. });
  344. // Windows via Bootcamp (!)
  345. if (0) {
  346. mergeIf(keyCodeToInfoTable,
  347. 'chrome-win', {
  348. 0xC0: { code: 'Quote', keyCap: '\'' }, // [USB: 0x34] '" (US Standard 101)
  349. 0xDE: { code: 'Backslash', keyCap: '\\' }, // [USB: 0x31] \| (US Standard 101)
  350. 0xDF: { code: 'Backquote', keyCap: '`' } // [USB: 0x35] `~ (US Standard 101)
  351. });
  352. mergeIf(keyCodeToInfoTable,
  353. 'ie', {
  354. 0xC0: { code: 'Quote', keyCap: '\'' }, // [USB: 0x34] '" (US Standard 101)
  355. 0xDE: { code: 'Backslash', keyCap: '\\' }, // [USB: 0x31] \| (US Standard 101)
  356. 0xDF: { code: 'Backquote', keyCap: '`' } // [USB: 0x35] `~ (US Standard 101)
  357. });
  358. }
  359. mergeIf(keyCodeToInfoTable,
  360. 'safari', {
  361. 0x03: { code: 'Enter' }, // [USB: 0x28] old Safari
  362. 0x19: { code: 'Tab' } // [USB: 0x2b] old Safari for Shift+Tab
  363. });
  364. mergeIf(keyCodeToInfoTable,
  365. 'ios', {
  366. 0x0A: { code: 'Enter', location: STANDARD } // [USB: 0x28]
  367. });
  368. mergeIf(keyCodeToInfoTable,
  369. 'safari-mac', {
  370. 0x5B: { code: 'OSLeft', location: LEFT }, // [USB: 0xe3]
  371. 0x5D: { code: 'OSRight', location: RIGHT }, // [USB: 0xe7]
  372. 0xE5: { code: 'KeyQ', keyCap: 'Q' } // [USB: 0x14] On alternate presses, Ctrl+Q sends this
  373. });
  374. //--------------------------------------------------------------------
  375. //
  376. // Identifier Mappings
  377. //
  378. //--------------------------------------------------------------------
  379. // Cases where newer-ish browsers send keyIdentifier which can be
  380. // used to disambiguate keys.
  381. // keyIdentifierTable[keyIdentifier] -> keyInfo
  382. var keyIdentifierTable = {};
  383. if ('cros' === os) {
  384. keyIdentifierTable['U+00A0'] = { code: 'ShiftLeft', location: LEFT };
  385. keyIdentifierTable['U+00A1'] = { code: 'ShiftRight', location: RIGHT };
  386. keyIdentifierTable['U+00A2'] = { code: 'ControlLeft', location: LEFT };
  387. keyIdentifierTable['U+00A3'] = { code: 'ControlRight', location: RIGHT };
  388. keyIdentifierTable['U+00A4'] = { code: 'AltLeft', location: LEFT };
  389. keyIdentifierTable['U+00A5'] = { code: 'AltRight', location: RIGHT };
  390. }
  391. if ('chrome-mac' === browser_os) {
  392. keyIdentifierTable['U+0010'] = { code: 'ContextMenu' };
  393. }
  394. if ('safari-mac' === browser_os) {
  395. keyIdentifierTable['U+0010'] = { code: 'ContextMenu' };
  396. }
  397. if ('ios' === os) {
  398. // These only generate keyup events
  399. keyIdentifierTable['U+0010'] = { code: 'Function' };
  400. keyIdentifierTable['U+001C'] = { code: 'ArrowLeft' };
  401. keyIdentifierTable['U+001D'] = { code: 'ArrowRight' };
  402. keyIdentifierTable['U+001E'] = { code: 'ArrowUp' };
  403. keyIdentifierTable['U+001F'] = { code: 'ArrowDown' };
  404. keyIdentifierTable['U+0001'] = { code: 'Home' }; // [USB: 0x4a] Fn + ArrowLeft
  405. keyIdentifierTable['U+0004'] = { code: 'End' }; // [USB: 0x4d] Fn + ArrowRight
  406. keyIdentifierTable['U+000B'] = { code: 'PageUp' }; // [USB: 0x4b] Fn + ArrowUp
  407. keyIdentifierTable['U+000C'] = { code: 'PageDown' }; // [USB: 0x4e] Fn + ArrowDown
  408. }
  409. //--------------------------------------------------------------------
  410. //
  411. // Location Mappings
  412. //
  413. //--------------------------------------------------------------------
  414. // Cases where newer-ish browsers send location/keyLocation which
  415. // can be used to disambiguate keys.
  416. // locationTable[location][keyCode] -> keyInfo
  417. var locationTable = [];
  418. locationTable[LEFT] = {
  419. 0x10: { code: 'ShiftLeft', location: LEFT }, // [USB: 0xe1]
  420. 0x11: { code: 'ControlLeft', location: LEFT }, // [USB: 0xe0]
  421. 0x12: { code: 'AltLeft', location: LEFT } // [USB: 0xe2]
  422. };
  423. locationTable[RIGHT] = {
  424. 0x10: { code: 'ShiftRight', location: RIGHT }, // [USB: 0xe5]
  425. 0x11: { code: 'ControlRight', location: RIGHT }, // [USB: 0xe4]
  426. 0x12: { code: 'AltRight', location: RIGHT } // [USB: 0xe6]
  427. };
  428. locationTable[NUMPAD] = {
  429. 0x0D: { code: 'NumpadEnter', location: NUMPAD } // [USB: 0x58]
  430. };
  431. mergeIf(locationTable[NUMPAD], 'moz', {
  432. 0x6D: { code: 'NumpadSubtract', location: NUMPAD }, // [USB: 0x56]
  433. 0x6B: { code: 'NumpadAdd', location: NUMPAD } // [USB: 0x57]
  434. });
  435. mergeIf(locationTable[LEFT], 'moz-mac', {
  436. 0xE0: { code: 'OSLeft', location: LEFT } // [USB: 0xe3]
  437. });
  438. mergeIf(locationTable[RIGHT], 'moz-mac', {
  439. 0xE0: { code: 'OSRight', location: RIGHT } // [USB: 0xe7]
  440. });
  441. mergeIf(locationTable[RIGHT], 'moz-win', {
  442. 0x5B: { code: 'OSRight', location: RIGHT } // [USB: 0xe7]
  443. });
  444. mergeIf(locationTable[RIGHT], 'mac', {
  445. 0x5D: { code: 'OSRight', location: RIGHT } // [USB: 0xe7]
  446. });
  447. mergeIf(locationTable[NUMPAD], 'chrome-mac', {
  448. 0x0C: { code: 'NumLock', location: NUMPAD } // [USB: 0x53]
  449. });
  450. mergeIf(locationTable[NUMPAD], 'safari-mac', {
  451. 0x0C: { code: 'NumLock', location: NUMPAD }, // [USB: 0x53]
  452. 0xBB: { code: 'NumpadAdd', location: NUMPAD }, // [USB: 0x57]
  453. 0xBD: { code: 'NumpadSubtract', location: NUMPAD }, // [USB: 0x56]
  454. 0xBE: { code: 'NumpadDecimal', location: NUMPAD }, // [USB: 0x63]
  455. 0xBF: { code: 'NumpadDivide', location: NUMPAD } // [USB: 0x54]
  456. });
  457. //--------------------------------------------------------------------
  458. //
  459. // Key Values
  460. //
  461. //--------------------------------------------------------------------
  462. // Mapping from `code` values to `key` values. Values defined at:
  463. // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3Events-key.html
  464. // Entries are only provided when `key` differs from `code`. If
  465. // printable, `shiftKey` has the shifted printable character. This
  466. // assumes US Standard 101 layout
  467. var codeToKeyTable = {
  468. // Modifier Keys
  469. ShiftLeft: { key: 'Shift' },
  470. ShiftRight: { key: 'Shift' },
  471. ControlLeft: { key: 'Control' },
  472. ControlRight: { key: 'Control' },
  473. AltLeft: { key: 'Alt' },
  474. AltRight: { key: 'Alt' },
  475. OSLeft: { key: 'OS' },
  476. OSRight: { key: 'OS' },
  477. // Whitespace Keys
  478. NumpadEnter: { key: 'Enter' },
  479. Space: { key: ' ' },
  480. // Printable Keys
  481. Digit0: { key: '0', shiftKey: ')' },
  482. Digit1: { key: '1', shiftKey: '!' },
  483. Digit2: { key: '2', shiftKey: '@' },
  484. Digit3: { key: '3', shiftKey: '#' },
  485. Digit4: { key: '4', shiftKey: '$' },
  486. Digit5: { key: '5', shiftKey: '%' },
  487. Digit6: { key: '6', shiftKey: '^' },
  488. Digit7: { key: '7', shiftKey: '&' },
  489. Digit8: { key: '8', shiftKey: '*' },
  490. Digit9: { key: '9', shiftKey: '(' },
  491. KeyA: { key: 'a', shiftKey: 'A' },
  492. KeyB: { key: 'b', shiftKey: 'B' },
  493. KeyC: { key: 'c', shiftKey: 'C' },
  494. KeyD: { key: 'd', shiftKey: 'D' },
  495. KeyE: { key: 'e', shiftKey: 'E' },
  496. KeyF: { key: 'f', shiftKey: 'F' },
  497. KeyG: { key: 'g', shiftKey: 'G' },
  498. KeyH: { key: 'h', shiftKey: 'H' },
  499. KeyI: { key: 'i', shiftKey: 'I' },
  500. KeyJ: { key: 'j', shiftKey: 'J' },
  501. KeyK: { key: 'k', shiftKey: 'K' },
  502. KeyL: { key: 'l', shiftKey: 'L' },
  503. KeyM: { key: 'm', shiftKey: 'M' },
  504. KeyN: { key: 'n', shiftKey: 'N' },
  505. KeyO: { key: 'o', shiftKey: 'O' },
  506. KeyP: { key: 'p', shiftKey: 'P' },
  507. KeyQ: { key: 'q', shiftKey: 'Q' },
  508. KeyR: { key: 'r', shiftKey: 'R' },
  509. KeyS: { key: 's', shiftKey: 'S' },
  510. KeyT: { key: 't', shiftKey: 'T' },
  511. KeyU: { key: 'u', shiftKey: 'U' },
  512. KeyV: { key: 'v', shiftKey: 'V' },
  513. KeyW: { key: 'w', shiftKey: 'W' },
  514. KeyX: { key: 'x', shiftKey: 'X' },
  515. KeyY: { key: 'y', shiftKey: 'Y' },
  516. KeyZ: { key: 'z', shiftKey: 'Z' },
  517. Numpad0: { key: '0' },
  518. Numpad1: { key: '1' },
  519. Numpad2: { key: '2' },
  520. Numpad3: { key: '3' },
  521. Numpad4: { key: '4' },
  522. Numpad5: { key: '5' },
  523. Numpad6: { key: '6' },
  524. Numpad7: { key: '7' },
  525. Numpad8: { key: '8' },
  526. Numpad9: { key: '9' },
  527. NumpadMultiply: { key: '*' },
  528. NumpadAdd: { key: '+' },
  529. NumpadComma: { key: ',' },
  530. NumpadSubtract: { key: '-' },
  531. NumpadDecimal: { key: '.' },
  532. NumpadDivide: { key: '/' },
  533. Semicolon: { key: ';', shiftKey: ':' },
  534. Equal: { key: '=', shiftKey: '+' },
  535. Comma: { key: ',', shiftKey: '<' },
  536. Minus: { key: '-', shiftKey: '_' },
  537. Period: { key: '.', shiftKey: '>' },
  538. Slash: { key: '/', shiftKey: '?' },
  539. Backquote: { key: '`', shiftKey: '~' },
  540. BracketLeft: { key: '[', shiftKey: '{' },
  541. Backslash: { key: '\\', shiftKey: '|' },
  542. BracketRight: { key: ']', shiftKey: '}' },
  543. Quote: { key: '\'', shiftKey: '"' },
  544. IntlBackslash: { key: '\\', shiftKey: '|' }
  545. };
  546. mergeIf(codeToKeyTable, 'mac', {
  547. OSLeft: { key: 'Meta' },
  548. OSRight: { key: 'Meta' }
  549. });
  550. // Corrections for 'key' names in older browsers (e.g. FF36-)
  551. // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key#Key_values
  552. var keyFixTable = {
  553. Esc: 'Escape',
  554. Nonconvert: 'NonConvert',
  555. Left: 'ArrowLeft',
  556. Up: 'ArrowUp',
  557. Right: 'ArrowRight',
  558. Down: 'ArrowDown',
  559. Del: 'Delete',
  560. Menu: 'ContextMenu',
  561. MediaNextTrack: 'MediaTrackNext',
  562. MediaPreviousTrack: 'MediaTrackPrevious',
  563. SelectMedia: 'MediaSelect',
  564. HalfWidth: 'Hankaku',
  565. FullWidth: 'Zenkaku',
  566. RomanCharacters: 'Romaji',
  567. Crsel: 'CrSel',
  568. Exsel: 'ExSel',
  569. Zoom: 'ZoomToggle'
  570. };
  571. //--------------------------------------------------------------------
  572. //
  573. // Exported Functions
  574. //
  575. //--------------------------------------------------------------------
  576. var codeTable = remap(keyCodeToInfoTable, 'code');
  577. try {
  578. var nativeLocation = nativeKeyboardEvent && ('location' in new KeyboardEvent(''));
  579. } catch (_) {}
  580. function keyInfoForEvent(event) {
  581. var keyCode = 'keyCode' in event ? event.keyCode : 'which' in event ? event.which : 0;
  582. var keyInfo = (function(){
  583. if (nativeLocation || 'keyLocation' in event) {
  584. var location = nativeLocation ? event.location : event.keyLocation;
  585. if (location && keyCode in locationTable[location]) {
  586. return locationTable[location][keyCode];
  587. }
  588. }
  589. if ('keyIdentifier' in event && event.keyIdentifier in keyIdentifierTable) {
  590. return keyIdentifierTable[event.keyIdentifier];
  591. }
  592. if (keyCode in keyCodeToInfoTable) {
  593. return keyCodeToInfoTable[keyCode];
  594. }
  595. return null;
  596. }());
  597. // TODO: Track these down and move to general tables
  598. if (0) {
  599. // TODO: Map these for newerish browsers?
  600. // TODO: iOS only?
  601. // TODO: Override with more common keyIdentifier name?
  602. switch (event.keyIdentifier) {
  603. case 'U+0010': keyInfo = { code: 'Function' }; break;
  604. case 'U+001C': keyInfo = { code: 'ArrowLeft' }; break;
  605. case 'U+001D': keyInfo = { code: 'ArrowRight' }; break;
  606. case 'U+001E': keyInfo = { code: 'ArrowUp' }; break;
  607. case 'U+001F': keyInfo = { code: 'ArrowDown' }; break;
  608. }
  609. }
  610. if (!keyInfo)
  611. return null;
  612. var key = (function() {
  613. var entry = codeToKeyTable[keyInfo.code];
  614. if (!entry) return keyInfo.code;
  615. return (event.shiftKey && 'shiftKey' in entry) ? entry.shiftKey : entry.key;
  616. }());
  617. return {
  618. code: keyInfo.code,
  619. key: key,
  620. location: keyInfo.location,
  621. keyCap: keyInfo.keyCap
  622. };
  623. }
  624. function queryKeyCap(code, locale) {
  625. code = String(code);
  626. if (!codeTable.hasOwnProperty(code)) return 'Undefined';
  627. if (locale && String(locale).toLowerCase() !== 'en-us') throw Error('Unsupported locale');
  628. var keyInfo = codeTable[code];
  629. return keyInfo.keyCap || keyInfo.code || 'Undefined';
  630. }
  631. if ('KeyboardEvent' in global && 'defineProperty' in Object) {
  632. (function() {
  633. function define(o, p, v) {
  634. if (p in o) return;
  635. Object.defineProperty(o, p, v);
  636. }
  637. define(KeyboardEvent.prototype, 'code', { get: function() {
  638. var keyInfo = keyInfoForEvent(this);
  639. return keyInfo ? keyInfo.code : '';
  640. }});
  641. // Fix for nonstandard `key` values (FF36-)
  642. if ('key' in KeyboardEvent.prototype) {
  643. var desc = Object.getOwnPropertyDescriptor(KeyboardEvent.prototype, 'key');
  644. Object.defineProperty(KeyboardEvent.prototype, 'key', { get: function() {
  645. var key = desc.get.call(this);
  646. return keyFixTable.hasOwnProperty(key) ? keyFixTable[key] : key;
  647. }});
  648. }
  649. define(KeyboardEvent.prototype, 'key', { get: function() {
  650. var keyInfo = keyInfoForEvent(this);
  651. return (keyInfo && 'key' in keyInfo) ? keyInfo.key : 'Unidentified';
  652. }});
  653. define(KeyboardEvent.prototype, 'location', { get: function() {
  654. var keyInfo = keyInfoForEvent(this);
  655. return (keyInfo && 'location' in keyInfo) ? keyInfo.location : STANDARD;
  656. }});
  657. define(KeyboardEvent.prototype, 'locale', { get: function() {
  658. return '';
  659. }});
  660. }());
  661. }
  662. if (!('queryKeyCap' in global.KeyboardEvent))
  663. global.KeyboardEvent.queryKeyCap = queryKeyCap;
  664. // Helper for IE8-
  665. global.identifyKey = function(event) {
  666. if ('code' in event)
  667. return;
  668. var keyInfo = keyInfoForEvent(event);
  669. event.code = keyInfo ? keyInfo.code : '';
  670. event.key = (keyInfo && 'key' in keyInfo) ? keyInfo.key : 'Unidentified';
  671. event.location = ('location' in event) ? event.location :
  672. ('keyLocation' in event) ? event.keyLocation :
  673. (keyInfo && 'location' in keyInfo) ? keyInfo.location : STANDARD;
  674. event.locale = '';
  675. };
  676. } (window));
  677. },{}],5:[function(require,module,exports){
  678. var CANNON = require('cannon'),
  679. math = require('./src/components/math');
  680. module.exports = {
  681. 'dynamic-body': require('./src/components/body/dynamic-body'),
  682. 'static-body': require('./src/components/body/static-body'),
  683. 'constraint': require('./src/components/constraint'),
  684. 'system': require('./src/system/physics'),
  685. registerAll: function (AFRAME) {
  686. if (this._registered) return;
  687. AFRAME = AFRAME || window.AFRAME;
  688. math.registerAll();
  689. if (!AFRAME.systems.physics) AFRAME.registerSystem('physics', this.system);
  690. if (!AFRAME.components['dynamic-body']) AFRAME.registerComponent('dynamic-body', this['dynamic-body']);
  691. if (!AFRAME.components['static-body']) AFRAME.registerComponent('static-body', this['static-body']);
  692. if (!AFRAME.components['constraint']) AFRAME.registerComponent('constraint', this['constraint']);
  693. this._registered = true;
  694. }
  695. };
  696. // Export CANNON.js.
  697. window.CANNON = window.CANNON || CANNON;
  698. },{"./src/components/body/dynamic-body":8,"./src/components/body/static-body":9,"./src/components/constraint":10,"./src/components/math":11,"./src/system/physics":15,"cannon":17}],6:[function(require,module,exports){
  699. /**
  700. * CANNON.shape2mesh
  701. *
  702. * Source: http://schteppe.github.io/cannon.js/build/cannon.demo.js
  703. * Author: @schteppe
  704. */
  705. var CANNON = require('cannon');
  706. CANNON.shape2mesh = function(body){
  707. var obj = new THREE.Object3D();
  708. for (var l = 0; l < body.shapes.length; l++) {
  709. var shape = body.shapes[l];
  710. var mesh;
  711. switch(shape.type){
  712. case CANNON.Shape.types.SPHERE:
  713. var sphere_geometry = new THREE.SphereGeometry( shape.radius, 8, 8);
  714. mesh = new THREE.Mesh( sphere_geometry, this.currentMaterial );
  715. break;
  716. case CANNON.Shape.types.PARTICLE:
  717. mesh = new THREE.Mesh( this.particleGeo, this.particleMaterial );
  718. var s = this.settings;
  719. mesh.scale.set(s.particleSize,s.particleSize,s.particleSize);
  720. break;
  721. case CANNON.Shape.types.PLANE:
  722. var geometry = new THREE.PlaneGeometry(10, 10, 4, 4);
  723. mesh = new THREE.Object3D();
  724. var submesh = new THREE.Object3D();
  725. var ground = new THREE.Mesh( geometry, this.currentMaterial );
  726. ground.scale.set(100, 100, 100);
  727. submesh.add(ground);
  728. ground.castShadow = true;
  729. ground.receiveShadow = true;
  730. mesh.add(submesh);
  731. break;
  732. case CANNON.Shape.types.BOX:
  733. var box_geometry = new THREE.BoxGeometry( shape.halfExtents.x*2,
  734. shape.halfExtents.y*2,
  735. shape.halfExtents.z*2 );
  736. mesh = new THREE.Mesh( box_geometry, this.currentMaterial );
  737. break;
  738. case CANNON.Shape.types.CONVEXPOLYHEDRON:
  739. var geo = new THREE.Geometry();
  740. // Add vertices
  741. for (var i = 0; i < shape.vertices.length; i++) {
  742. var v = shape.vertices[i];
  743. geo.vertices.push(new THREE.Vector3(v.x, v.y, v.z));
  744. }
  745. for(var i=0; i < shape.faces.length; i++){
  746. var face = shape.faces[i];
  747. // add triangles
  748. var a = face[0];
  749. for (var j = 1; j < face.length - 1; j++) {
  750. var b = face[j];
  751. var c = face[j + 1];
  752. geo.faces.push(new THREE.Face3(a, b, c));
  753. }
  754. }
  755. geo.computeBoundingSphere();
  756. geo.computeFaceNormals();
  757. mesh = new THREE.Mesh( geo, this.currentMaterial );
  758. break;
  759. case CANNON.Shape.types.HEIGHTFIELD:
  760. var geometry = new THREE.Geometry();
  761. var v0 = new CANNON.Vec3();
  762. var v1 = new CANNON.Vec3();
  763. var v2 = new CANNON.Vec3();
  764. for (var xi = 0; xi < shape.data.length - 1; xi++) {
  765. for (var yi = 0; yi < shape.data[xi].length - 1; yi++) {
  766. for (var k = 0; k < 2; k++) {
  767. shape.getConvexTrianglePillar(xi, yi, k===0);
  768. v0.copy(shape.pillarConvex.vertices[0]);
  769. v1.copy(shape.pillarConvex.vertices[1]);
  770. v2.copy(shape.pillarConvex.vertices[2]);
  771. v0.vadd(shape.pillarOffset, v0);
  772. v1.vadd(shape.pillarOffset, v1);
  773. v2.vadd(shape.pillarOffset, v2);
  774. geometry.vertices.push(
  775. new THREE.Vector3(v0.x, v0.y, v0.z),
  776. new THREE.Vector3(v1.x, v1.y, v1.z),
  777. new THREE.Vector3(v2.x, v2.y, v2.z)
  778. );
  779. var i = geometry.vertices.length - 3;
  780. geometry.faces.push(new THREE.Face3(i, i+1, i+2));
  781. }
  782. }
  783. }
  784. geometry.computeBoundingSphere();
  785. geometry.computeFaceNormals();
  786. mesh = new THREE.Mesh(geometry, this.currentMaterial);
  787. break;
  788. case CANNON.Shape.types.TRIMESH:
  789. var geometry = new THREE.Geometry();
  790. var v0 = new CANNON.Vec3();
  791. var v1 = new CANNON.Vec3();
  792. var v2 = new CANNON.Vec3();
  793. for (var i = 0; i < shape.indices.length / 3; i++) {
  794. shape.getTriangleVertices(i, v0, v1, v2);
  795. geometry.vertices.push(
  796. new THREE.Vector3(v0.x, v0.y, v0.z),
  797. new THREE.Vector3(v1.x, v1.y, v1.z),
  798. new THREE.Vector3(v2.x, v2.y, v2.z)
  799. );
  800. var j = geometry.vertices.length - 3;
  801. geometry.faces.push(new THREE.Face3(j, j+1, j+2));
  802. }
  803. geometry.computeBoundingSphere();
  804. geometry.computeFaceNormals();
  805. mesh = new THREE.Mesh(geometry, this.currentMaterial);
  806. break;
  807. default:
  808. throw "Visual type not recognized: "+shape.type;
  809. }
  810. mesh.receiveShadow = true;
  811. mesh.castShadow = true;
  812. if(mesh.children){
  813. for(var i=0; i<mesh.children.length; i++){
  814. mesh.children[i].castShadow = true;
  815. mesh.children[i].receiveShadow = true;
  816. if(mesh.children[i]){
  817. for(var j=0; j<mesh.children[i].length; j++){
  818. mesh.children[i].children[j].castShadow = true;
  819. mesh.children[i].children[j].receiveShadow = true;
  820. }
  821. }
  822. }
  823. }
  824. var o = body.shapeOffsets[l];
  825. var q = body.shapeOrientations[l];
  826. mesh.position.set(o.x, o.y, o.z);
  827. mesh.quaternion.set(q.x, q.y, q.z, q.w);
  828. obj.add(mesh);
  829. }
  830. return obj;
  831. };
  832. module.exports = CANNON.shape2mesh;
  833. },{"cannon":17}],7:[function(require,module,exports){
  834. var CANNON = require('cannon'),
  835. mesh2shape = require('three-to-cannon');
  836. require('../../../lib/CANNON-shape2mesh');
  837. module.exports = {
  838. schema: {
  839. shape: {default: 'auto', oneOf: ['auto', 'box', 'cylinder', 'sphere', 'hull', 'none']},
  840. cylinderAxis: {default: 'y', oneOf: ['x', 'y', 'z']},
  841. sphereRadius: {default: NaN}
  842. },
  843. /**
  844. * Initializes a body component, assigning it to the physics system and binding listeners for
  845. * parsing the elements geometry.
  846. */
  847. init: function () {
  848. this.system = this.el.sceneEl.systems.physics;
  849. if (this.el.sceneEl.hasLoaded) {
  850. this.initBody();
  851. } else {
  852. this.el.sceneEl.addEventListener('loaded', this.initBody.bind(this));
  853. }
  854. },
  855. /**
  856. * Parses an element's geometry and component metadata to create a CANNON.Body instance for the
  857. * component.
  858. */
  859. initBody: function () {
  860. var shape,
  861. el = this.el,
  862. data = this.data,
  863. pos = el.getAttribute('position');
  864. this.body = new CANNON.Body({
  865. mass: data.mass || 0,
  866. material: this.system.material,
  867. position: new CANNON.Vec3(pos.x, pos.y, pos.z),
  868. linearDamping: data.linearDamping,
  869. angularDamping: data.angularDamping
  870. });
  871. // Matrix World must be updated at root level, if scale is to be applied – updateMatrixWorld()
  872. // only checks an object's parent, not the rest of the ancestors. Hence, a wrapping entity with
  873. // scale="0.5 0.5 0.5" will be ignored.
  874. // Reference: https://github.com/mrdoob/three.js/blob/master/src/core/Object3D.js#L511-L541
  875. // Potential fix: https://github.com/mrdoob/three.js/pull/7019
  876. this.el.object3D.updateMatrixWorld(true);
  877. if(data.shape !== 'none') {
  878. var options = data.shape === 'auto' ? undefined : AFRAME.utils.extend({}, this.data, {
  879. type: mesh2shape.Type[data.shape.toUpperCase()]
  880. });
  881. shape = mesh2shape(this.el.object3D, options);
  882. if (!shape) {
  883. this.el.addEventListener('model-loaded', this.initBody.bind(this));
  884. return;
  885. }
  886. this.body.addShape(shape, shape.offset, shape.orientation);
  887. // Show wireframe
  888. if (this.system.debug) {
  889. this.createWireframe(this.body, shape);
  890. }
  891. }
  892. // Apply rotation
  893. var rot = el.getAttribute('rotation');
  894. this.body.quaternion.setFromEuler(
  895. THREE.Math.degToRad(rot.x),
  896. THREE.Math.degToRad(rot.y),
  897. THREE.Math.degToRad(rot.z),
  898. 'XYZ'
  899. ).normalize();
  900. this.el.body = this.body;
  901. this.body.el = this.el;
  902. this.isLoaded = true;
  903. // If component wasn't initialized when play() was called, finish up.
  904. if (this.isPlaying) {
  905. this._play();
  906. }
  907. this.el.emit('body-loaded', {body: this.el.body});
  908. },
  909. /**
  910. * Registers the component with the physics system, if ready.
  911. */
  912. play: function () {
  913. if (this.isLoaded) this._play();
  914. },
  915. /**
  916. * Internal helper to register component with physics system.
  917. */
  918. _play: function () {
  919. this.system.addBehavior(this, this.system.Phase.SIMULATE);
  920. this.system.addBody(this.body);
  921. if (this.wireframe) this.el.sceneEl.object3D.add(this.wireframe);
  922. this.syncToPhysics();
  923. },
  924. /**
  925. * Unregisters the component with the physics system.
  926. */
  927. pause: function () {
  928. if (!this.isLoaded) return;
  929. this.system.removeBehavior(this, this.system.Phase.SIMULATE);
  930. this.system.removeBody(this.body);
  931. if (this.wireframe) this.el.sceneEl.object3D.remove(this.wireframe);
  932. },
  933. /**
  934. * Removes the component and all physics and scene side effects.
  935. */
  936. remove: function () {
  937. this.pause();
  938. delete this.body.el;
  939. delete this.body;
  940. delete this.el.body;
  941. delete this.wireframe;
  942. },
  943. /**
  944. * Creates a wireframe for the body, for debugging.
  945. * TODO(donmccurdy) – Refactor this into a standalone utility or component.
  946. * @param {CANNON.Body} body
  947. * @param {CANNON.Shape} shape
  948. */
  949. createWireframe: function (body, shape) {
  950. var offset = shape.offset,
  951. orientation = shape.orientation,
  952. mesh = CANNON.shape2mesh(body).children[0];
  953. this.wireframe = new THREE.LineSegments(
  954. new THREE.EdgesGeometry(mesh.geometry),
  955. new THREE.LineBasicMaterial({color: 0xff0000})
  956. );
  957. if (offset) {
  958. this.wireframe.offset = offset.clone();
  959. }
  960. if (orientation) {
  961. orientation.inverse(orientation);
  962. this.wireframe.orientation = new THREE.Quaternion(
  963. orientation.x,
  964. orientation.y,
  965. orientation.z,
  966. orientation.w
  967. );
  968. }
  969. this.syncWireframe();
  970. },
  971. /**
  972. * Updates the debugging wireframe's position and rotation.
  973. */
  974. syncWireframe: function () {
  975. var offset,
  976. wireframe = this.wireframe;
  977. if (!this.wireframe) return;
  978. // Apply rotation. If the shape required custom orientation, also apply
  979. // that on the wireframe.
  980. wireframe.quaternion.copy(this.body.quaternion);
  981. if (wireframe.orientation) {
  982. wireframe.quaternion.multiply(wireframe.orientation);
  983. }
  984. // Apply position. If the shape required custom offset, also apply that on
  985. // the wireframe.
  986. wireframe.position.copy(this.body.position);
  987. if (wireframe.offset) {
  988. offset = wireframe.offset.clone().applyQuaternion(wireframe.quaternion);
  989. wireframe.position.add(offset);
  990. }
  991. wireframe.updateMatrix();
  992. },
  993. /**
  994. * Updates the CANNON.Body instance's position, velocity, and rotation, based on the scene.
  995. */
  996. syncToPhysics: (function () {
  997. var q = new THREE.Quaternion(),
  998. v = new THREE.Vector3();
  999. return function () {
  1000. var el = this.el,
  1001. parentEl = el.parentEl,
  1002. body = this.body;
  1003. if (!body) return;
  1004. if (el.components.velocity) body.velocity.copy(el.getAttribute('velocity'));
  1005. if (parentEl.isScene) {
  1006. body.quaternion.copy(el.object3D.quaternion);
  1007. body.position.copy(el.object3D.position);
  1008. } else {
  1009. el.object3D.getWorldQuaternion(q);
  1010. body.quaternion.copy(q);
  1011. el.object3D.getWorldPosition(v);
  1012. body.position.copy(v);
  1013. }
  1014. if (this.wireframe) this.syncWireframe();
  1015. };
  1016. }()),
  1017. /**
  1018. * Updates the scene object's position and rotation, based on the physics simulation.
  1019. */
  1020. syncFromPhysics: (function () {
  1021. var v = new THREE.Vector3(),
  1022. q1 = new THREE.Quaternion(),
  1023. q2 = new THREE.Quaternion();
  1024. return function () {
  1025. var el = this.el,
  1026. parentEl = el.parentEl,
  1027. body = this.body;
  1028. if (!body) return;
  1029. if (parentEl.isScene) {
  1030. el.setAttribute('quaternion', body.quaternion);
  1031. el.setAttribute('position', body.position);
  1032. } else {
  1033. // TODO - Nested rotation doesn't seem to be working as expected.
  1034. q1.copy(body.quaternion);
  1035. parentEl.object3D.getWorldQuaternion(q2);
  1036. q1.multiply(q2.inverse());
  1037. el.setAttribute('quaternion', {x: q1.x, y: q1.y, z: q1.z, w: q1.w});
  1038. v.copy(body.position);
  1039. parentEl.object3D.worldToLocal(v);
  1040. el.setAttribute('position', {x: v.x, y: v.y, z: v.z});
  1041. }
  1042. if (this.wireframe) this.syncWireframe();
  1043. };
  1044. }())
  1045. };
  1046. },{"../../../lib/CANNON-shape2mesh":6,"cannon":17,"three-to-cannon":73}],8:[function(require,module,exports){
  1047. var Body = require('./body');
  1048. /**
  1049. * Dynamic body.
  1050. *
  1051. * Moves according to physics simulation, and may collide with other objects.
  1052. */
  1053. module.exports = AFRAME.utils.extend({}, Body, {
  1054. dependencies: ['quaternion', 'velocity'],
  1055. schema: AFRAME.utils.extend({}, Body.schema, {
  1056. mass: { default: 5 },
  1057. linearDamping: { default: 0.01 },
  1058. angularDamping: { default: 0.01 }
  1059. }),
  1060. step: function () {
  1061. this.syncFromPhysics();
  1062. }
  1063. });
  1064. },{"./body":7}],9:[function(require,module,exports){
  1065. var Body = require('./body');
  1066. /**
  1067. * Static body.
  1068. *
  1069. * Solid body with a fixed position. Unaffected by gravity and collisions, but
  1070. * other objects may collide with it.
  1071. */
  1072. module.exports = AFRAME.utils.extend({}, Body, {
  1073. step: function () {
  1074. this.syncToPhysics();
  1075. }
  1076. });
  1077. },{"./body":7}],10:[function(require,module,exports){
  1078. var CANNON = require('cannon');
  1079. module.exports = {
  1080. dependencies: ['dynamic-body'],
  1081. multiple: true,
  1082. schema: {
  1083. // Type of constraint.
  1084. type: {default: 'lock', oneOf: ['coneTwist', 'distance', 'hinge', 'lock', 'pointToPoint']},
  1085. // Target (other) body for the constraint.
  1086. target: {type: 'selector'},
  1087. // Maximum force that should be applied to constraint the bodies.
  1088. maxForce: {default: 1e6, min: 0},
  1089. // If true, bodies can collide when they are connected.
  1090. collideConnected: {default: true},
  1091. // Wake up bodies when connected.
  1092. wakeUpBodies: {default: true},
  1093. // The distance to be kept between the bodies. If 0, will be set to current distance.
  1094. distance: {default: 0, min: 0},
  1095. // Offset of the hinge or point-to-point constraint, defined locally in the body.
  1096. pivot: {type: 'vec3'},
  1097. targetPivot: {type: 'vec3'},
  1098. // An axis that each body can rotate around, defined locally to that body.
  1099. axis: {type: 'vec3', default: { x: 0, y: 0, z: 1 }},
  1100. targetAxis: {type: 'vec3', default: { x: 0, y: 0, z: 1}}
  1101. },
  1102. init: function () {
  1103. this.system = this.el.sceneEl.systems.physics;
  1104. this.constraint = /* {CANNON.Constraint} */ null;
  1105. },
  1106. remove: function () {
  1107. if (!this.constraint) return;
  1108. this.system.world.removeConstraint(this.constraint);
  1109. this.constraint = null;
  1110. },
  1111. update: function () {
  1112. var el = this.el,
  1113. data = this.data;
  1114. this.remove();
  1115. if (!el.body || !data.target.body) {
  1116. (el.body ? data.target : el).addEventListener('body-loaded', this.update.bind(this, {}));
  1117. return;
  1118. }
  1119. this.constraint = this.createConstraint();
  1120. this.system.world.addConstraint(this.constraint);
  1121. },
  1122. /**
  1123. * Creates a new constraint, given current component data. The CANNON.js constructors are a bit
  1124. * different for each constraint type.
  1125. * @return {CANNON.Constraint}
  1126. */
  1127. createConstraint: function () {
  1128. var data = this.data,
  1129. pivot = new CANNON.Vec3(data.pivot.x, data.pivot.y, data.pivot.z),
  1130. targetPivot = new CANNON.Vec3(data.targetPivot.x, data.targetPivot.y, data.targetPivot.z),
  1131. axis = new CANNON.Vec3(data.axis.x, data.axis.y, data.axis.z),
  1132. targetAxis= new CANNON.Vec3(data.targetAxis.x, data.targetAxis.y, data.targetAxis.z);
  1133. var constraint;
  1134. switch (data.type) {
  1135. case 'lock':
  1136. constraint = new CANNON.LockConstraint(
  1137. this.el.body,
  1138. data.target.body,
  1139. {maxForce: data.maxForce}
  1140. );
  1141. break;
  1142. case 'distance':
  1143. constraint = new CANNON.DistanceConstraint(
  1144. this.el.body,
  1145. data.target.body,
  1146. data.distance,
  1147. data.maxForce
  1148. );
  1149. break;
  1150. case 'hinge':
  1151. constraint = new CANNON.HingeConstraint(
  1152. this.el.body,
  1153. data.target.body, {
  1154. pivotA: pivot,
  1155. pivotB: targetPivot,
  1156. axisA: axis,
  1157. axisB: targetAxis,
  1158. maxForce: data.maxForce
  1159. });
  1160. break;
  1161. case 'coneTwist':
  1162. constraint = new CANNON.ConeTwistConstraint(
  1163. this.el.body,
  1164. data.target.body, {
  1165. pivotA: pivot,
  1166. pivotB: targetPivot,
  1167. axisA: axis,
  1168. axisB: targetAxis,
  1169. maxForce: data.maxForce
  1170. });
  1171. break;
  1172. case 'pointToPoint':
  1173. constraint = new CANNON.PointToPointConstraint(
  1174. this.el.body,
  1175. pivot,
  1176. data.target.body,
  1177. targetPivot,
  1178. data.maxForce);
  1179. break;
  1180. default:
  1181. throw new Error('[constraint] Unexpected type: ' + data.type);
  1182. }
  1183. constraint.collideConnected = data.collideConnected;
  1184. return constraint;
  1185. }
  1186. };
  1187. },{"cannon":17}],11:[function(require,module,exports){
  1188. module.exports = {
  1189. 'velocity': require('./velocity'),
  1190. 'quaternion': require('./quaternion'),
  1191. registerAll: function (AFRAME) {
  1192. if (this._registered) return;
  1193. AFRAME = AFRAME || window.AFRAME;
  1194. if (!AFRAME.components['velocity']) AFRAME.registerComponent('velocity', this.velocity);
  1195. if (!AFRAME.components['quaternion']) AFRAME.registerComponent('quaternion', this.quaternion);
  1196. this._registered = true;
  1197. }
  1198. };
  1199. },{"./quaternion":12,"./velocity":13}],12:[function(require,module,exports){
  1200. /**
  1201. * Quaternion.
  1202. *
  1203. * Represents orientation of object in three dimensions. Similar to `rotation`
  1204. * component, but avoids problems of gimbal lock.
  1205. *
  1206. * See: https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
  1207. */
  1208. module.exports = {
  1209. schema: {type: 'vec4'},
  1210. play: function () {
  1211. var el = this.el,
  1212. q = el.object3D.quaternion;
  1213. if (el.hasAttribute('rotation')) {
  1214. el.components.rotation.update();
  1215. el.setAttribute('quaternion', {x: q.x, y: q.y, z: q.z, w: q.w});
  1216. el.removeAttribute('rotation');
  1217. this.update();
  1218. }
  1219. },
  1220. update: function () {
  1221. var data = this.data;
  1222. this.el.object3D.quaternion.set(data.x, data.y, data.z, data.w);
  1223. }
  1224. };
  1225. },{}],13:[function(require,module,exports){
  1226. /**
  1227. * Velocity, in m/s.
  1228. */
  1229. module.exports = {
  1230. schema: {type: 'vec3'},
  1231. init: function () {
  1232. this.system = this.el.sceneEl.systems.physics;
  1233. if (this.system) {
  1234. this.system.addBehavior(this, this.system.Phase.RENDER);
  1235. }
  1236. },
  1237. remove: function () {
  1238. if (this.system) {
  1239. this.system.removeBehavior(this, this.system.Phase.RENDER);
  1240. }
  1241. },
  1242. tick: function (t, dt) {
  1243. if (!dt) return;
  1244. if (this.system) return;
  1245. this.step(t, dt);
  1246. },
  1247. step: function (t, dt) {
  1248. if (!dt) return;
  1249. var physics = this.el.sceneEl.systems.physics || {data: {maxInterval: 1 / 60}},
  1250. // TODO - There's definitely a bug with getComputedAttribute and el.data.
  1251. velocity = this.el.getAttribute('velocity') || {x: 0, y: 0, z: 0},
  1252. position = this.el.getAttribute('position') || {x: 0, y: 0, z: 0};
  1253. dt = Math.min(dt, physics.data.maxInterval * 1000);
  1254. this.el.setAttribute('position', {
  1255. x: position.x + velocity.x * dt / 1000,
  1256. y: position.y + velocity.y * dt / 1000,
  1257. z: position.z + velocity.z * dt / 1000
  1258. });
  1259. }
  1260. };
  1261. },{}],14:[function(require,module,exports){
  1262. module.exports = {
  1263. GRAVITY: -9.8,
  1264. MAX_INTERVAL: 4 / 60,
  1265. ITERATIONS: 10,
  1266. CONTACT_MATERIAL: {
  1267. friction: 0.01,
  1268. restitution: 0.3,
  1269. contactEquationStiffness: 1e8,
  1270. contactEquationRelaxation: 3,
  1271. frictionEquationStiffness: 1e8,
  1272. frictionEquationRegularization: 3
  1273. }
  1274. };
  1275. },{}],15:[function(require,module,exports){
  1276. var CANNON = require('cannon'),
  1277. CONSTANTS = require('../constants'),
  1278. C_GRAV = CONSTANTS.GRAVITY,
  1279. C_MAT = CONSTANTS.CONTACT_MATERIAL;
  1280. /**
  1281. * Physics system.
  1282. */
  1283. module.exports = {
  1284. schema: {
  1285. gravity: { default: C_GRAV },
  1286. iterations: { default: CONSTANTS.ITERATIONS },
  1287. friction: { default: C_MAT.friction },
  1288. restitution: { default: C_MAT.restitution },
  1289. contactEquationStiffness: { default: C_MAT.contactEquationStiffness },
  1290. contactEquationRelaxation: { default: C_MAT.contactEquationRelaxation },
  1291. frictionEquationStiffness: { default: C_MAT.frictionEquationStiffness },
  1292. frictionEquationRegularization: { default: C_MAT.frictionEquationRegularization },
  1293. // Never step more than four frames at once. Effectively pauses the scene
  1294. // when out of focus, and prevents weird "jumps" when focus returns.
  1295. maxInterval: { default: 4 / 60 },
  1296. // If true, show wireframes around physics bodies.
  1297. debug: { default: false },
  1298. },
  1299. /**
  1300. * Update phases, used to separate physics simulation from updates to A-Frame scene.
  1301. * @enum {string}
  1302. */
  1303. Phase: {
  1304. SIMULATE: 'sim',
  1305. RENDER: 'render'
  1306. },
  1307. /**
  1308. * Initializes the physics system.
  1309. */
  1310. init: function () {
  1311. var data = this.data;
  1312. // If true, show wireframes around physics bodies.
  1313. this.debug = data.debug;
  1314. this.children = {};
  1315. this.children[this.Phase.SIMULATE] = [];
  1316. this.children[this.Phase.RENDER] = [];
  1317. this.listeners = {};
  1318. this.world = new CANNON.World();
  1319. this.world.quatNormalizeSkip = 0;
  1320. this.world.quatNormalizeFast = false;
  1321. // this.world.solver.setSpookParams(300,10);
  1322. this.world.solver.iterations = data.iterations;
  1323. this.world.gravity.set(0, data.gravity, 0);
  1324. this.world.broadphase = new CANNON.NaiveBroadphase();
  1325. this.material = new CANNON.Material({name: 'defaultMaterial'});
  1326. this.contactMaterial = new CANNON.ContactMaterial(this.material, this.material, {
  1327. friction: data.friction,
  1328. restitution: data.restitution,
  1329. contactEquationStiffness: data.contactEquationStiffness,
  1330. contactEquationRelaxation: data.contactEquationRelaxation,
  1331. frictionEquationStiffness: data.frictionEquationStiffness,
  1332. frictionEquationRegularization: data.frictionEquationRegularization
  1333. });
  1334. this.world.addContactMaterial(this.contactMaterial);
  1335. },
  1336. /**
  1337. * Updates the physics world on each tick of the A-Frame scene. It would be
  1338. * entirely possible to separate the two – updating physics more or less
  1339. * frequently than the scene – if greater precision or performance were
  1340. * necessary.
  1341. * @param {number} t
  1342. * @param {number} dt
  1343. */
  1344. tick: function (t, dt) {
  1345. if (!dt) return;
  1346. this.world.step(Math.min(dt / 1000, this.data.maxInterval));
  1347. var i;
  1348. for (i = 0; i < this.children[this.Phase.SIMULATE].length; i++) {
  1349. this.children[this.Phase.SIMULATE][i].step(t, dt);
  1350. }
  1351. for (i = 0; i < this.children[this.Phase.RENDER].length; i++) {
  1352. this.children[this.Phase.RENDER][i].step(t, dt);
  1353. }
  1354. },
  1355. /**
  1356. * Adds a body to the scene, and binds collision events to the element.
  1357. * @param {CANNON.Body} body
  1358. */
  1359. addBody: function (body) {
  1360. this.listeners[body.id] = function (e) { body.el.emit('collide', e); };
  1361. body.addEventListener('collide', this.listeners[body.id]);
  1362. this.world.addBody(body);
  1363. },
  1364. /**
  1365. * Removes a body, and its listeners, from the scene.
  1366. * @param {CANNON.Body} body
  1367. */
  1368. removeBody: function (body) {
  1369. body.removeEventListener('collide', this.listeners[body.id]);
  1370. delete this.listeners[body.id];
  1371. this.world.removeBody(body);
  1372. },
  1373. /**
  1374. * Adds a component instance to the system, to be invoked on each tick during
  1375. * the given phase.
  1376. * @param {Component} component
  1377. * @param {string} phase
  1378. */
  1379. addBehavior: function (component, phase) {
  1380. this.children[phase].push(component);
  1381. },
  1382. /**
  1383. * Removes a component instance from the system.
  1384. * @param {Component} component
  1385. * @param {string} phase
  1386. */
  1387. removeBehavior: function (component, phase) {
  1388. this.children[phase].splice(this.children[phase].indexOf(component), 1);
  1389. },
  1390. /**
  1391. * Sets an option on the physics system, affecting future simulation steps.
  1392. * @param {string} opt
  1393. * @param {mixed} value
  1394. */
  1395. update: function (previousData) {
  1396. var data = this.data;
  1397. if (data.debug !== previousData.debug) {
  1398. console.warn('[physics] `debug` cannot be changed dynamically.');
  1399. }
  1400. if (data.maxInterval !== previousData.maxInterval); // noop;
  1401. if (data.gravity !== previousData.gravity) this.world.gravity.set(0, data.gravity, 0);
  1402. this.contactMaterial.friction = data.friction;
  1403. this.contactMaterial.restitution = data.restitution;
  1404. this.contactMaterial.contactEquationStiffness = data.contactEquationStiffness;
  1405. this.contactMaterial.contactEquationRelaxation = data.contactEquationRelaxation;
  1406. this.contactMaterial.frictionEquationStiffness = data.frictionEquationStiffness;
  1407. this.contactMaterial.frictionEquationRegularization = data.frictionEquationRegularization;
  1408. }
  1409. };
  1410. },{"../constants":14,"cannon":17}],16:[function(require,module,exports){
  1411. module.exports={
  1412. "_from": "github:donmccurdy/cannon.js#v0.6.2-dev1",
  1413. "_id": "cannon@0.6.2",
  1414. "_inBundle": false,
  1415. "_integrity": "sha1-kuhwtr7Hd8jqU3mcndOx2tmf0RU=",
  1416. "_location": "/cannon",
  1417. "_phantomChildren": {},
  1418. "_requested": {
  1419. "type": "git",
  1420. "raw": "cannon@github:donmccurdy/cannon.js#v0.6.2-dev1",
  1421. "name": "cannon",
  1422. "escapedName": "cannon",
  1423. "rawSpec": "github:donmccurdy/cannon.js#v0.6.2-dev1",
  1424. "saveSpec": "github:donmccurdy/cannon.js#v0.6.2-dev1",
  1425. "fetchSpec": null,
  1426. "gitCommittish": "v0.6.2-dev1"
  1427. },
  1428. "_requiredBy": [
  1429. "/aframe-physics-system"
  1430. ],
  1431. "_resolved": "github:donmccurdy/cannon.js#022e8ba53fa83abf0ad8a0e4fd08623123838a17",
  1432. "_spec": "cannon@github:donmccurdy/cannon.js#v0.6.2-dev1",
  1433. "_where": "/Users/donmccurdy/Documents/Projects/aframe-extras/node_modules/aframe-physics-system",
  1434. "author": {
  1435. "name": "Stefan Hedman",
  1436. "email": "schteppe@gmail.com",
  1437. "url": "http://steffe.se"
  1438. },
  1439. "bugs": {
  1440. "url": "https://github.com/schteppe/cannon.js/issues"
  1441. },
  1442. "bundleDependencies": false,
  1443. "dependencies": {},
  1444. "deprecated": false,
  1445. "description": "A lightweight 3D physics engine written in JavaScript.",
  1446. "devDependencies": {
  1447. "browserify": "*",
  1448. "grunt": "~0.4.0",
  1449. "grunt-browserify": "^2.1.4",
  1450. "grunt-contrib-concat": "~0.1.3",
  1451. "grunt-contrib-jshint": "~0.1.1",
  1452. "grunt-contrib-nodeunit": "^0.4.1",
  1453. "grunt-contrib-uglify": "^0.5.1",
  1454. "grunt-contrib-yuidoc": "^0.5.2",
  1455. "jshint": "latest",
  1456. "nodeunit": "^0.9.0",
  1457. "uglify-js": "latest"
  1458. },
  1459. "engines": {
  1460. "node": "*"
  1461. },
  1462. "homepage": "https://github.com/schteppe/cannon.js",
  1463. "keywords": [
  1464. "cannon.js",
  1465. "cannon",
  1466. "physics",
  1467. "engine",
  1468. "3d"
  1469. ],
  1470. "licenses": [
  1471. {
  1472. "type": "MIT"
  1473. }
  1474. ],
  1475. "main": "./src/Cannon.js",
  1476. "name": "cannon",
  1477. "repository": {
  1478. "type": "git",
  1479. "url": "git+https://github.com/schteppe/cannon.js.git"
  1480. },
  1481. "version": "0.6.2"
  1482. }
  1483. },{}],17:[function(require,module,exports){
  1484. // Export classes
  1485. module.exports = {
  1486. version : require('../package.json').version,
  1487. AABB : require('./collision/AABB'),
  1488. ArrayCollisionMatrix : require('./collision/ArrayCollisionMatrix'),
  1489. Body : require('./objects/Body'),
  1490. Box : require('./shapes/Box'),
  1491. Broadphase : require('./collision/Broadphase'),
  1492. Constraint : require('./constraints/Constraint'),
  1493. ContactEquation : require('./equations/ContactEquation'),
  1494. Narrowphase : require('./world/Narrowphase'),
  1495. ConeTwistConstraint : require('./constraints/ConeTwistConstraint'),
  1496. ContactMaterial : require('./material/ContactMaterial'),
  1497. ConvexPolyhedron : require('./shapes/ConvexPolyhedron'),
  1498. Cylinder : require('./shapes/Cylinder'),
  1499. DistanceConstraint : require('./constraints/DistanceConstraint'),
  1500. Equation : require('./equations/Equation'),
  1501. EventTarget : require('./utils/EventTarget'),
  1502. FrictionEquation : require('./equations/FrictionEquation'),
  1503. GSSolver : require('./solver/GSSolver'),
  1504. GridBroadphase : require('./collision/GridBroadphase'),
  1505. Heightfield : require('./shapes/Heightfield'),
  1506. HingeConstraint : require('./constraints/HingeConstraint'),
  1507. LockConstraint : require('./constraints/LockConstraint'),
  1508. Mat3 : require('./math/Mat3'),
  1509. Material : require('./material/Material'),
  1510. NaiveBroadphase : require('./collision/NaiveBroadphase'),
  1511. ObjectCollisionMatrix : require('./collision/ObjectCollisionMatrix'),
  1512. Pool : require('./utils/Pool'),
  1513. Particle : require('./shapes/Particle'),
  1514. Plane : require('./shapes/Plane'),
  1515. PointToPointConstraint : require('./constraints/PointToPointConstraint'),
  1516. Quaternion : require('./math/Quaternion'),
  1517. Ray : require('./collision/Ray'),
  1518. RaycastVehicle : require('./objects/RaycastVehicle'),
  1519. RaycastResult : require('./collision/RaycastResult'),
  1520. RigidVehicle : require('./objects/RigidVehicle'),
  1521. RotationalEquation : require('./equations/RotationalEquation'),
  1522. RotationalMotorEquation : require('./equations/RotationalMotorEquation'),
  1523. SAPBroadphase : require('./collision/SAPBroadphase'),
  1524. SPHSystem : require('./objects/SPHSystem'),
  1525. Shape : require('./shapes/Shape'),
  1526. Solver : require('./solver/Solver'),
  1527. Sphere : require('./shapes/Sphere'),
  1528. SplitSolver : require('./solver/SplitSolver'),
  1529. Spring : require('./objects/Spring'),
  1530. Transform : require('./math/Transform'),
  1531. Trimesh : require('./shapes/Trimesh'),
  1532. Vec3 : require('./math/Vec3'),
  1533. Vec3Pool : require('./utils/Vec3Pool'),
  1534. World : require('./world/World'),
  1535. };
  1536. },{"../package.json":16,"./collision/AABB":18,"./collision/ArrayCollisionMatrix":19,"./collision/Broadphase":20,"./collision/GridBroadphase":21,"./collision/NaiveBroadphase":22,"./collision/ObjectCollisionMatrix":23,"./collision/Ray":25,"./collision/RaycastResult":26,"./collision/SAPBroadphase":27,"./constraints/ConeTwistConstraint":28,"./constraints/Constraint":29,"./constraints/DistanceConstraint":30,"./constraints/HingeConstraint":31,"./constraints/LockConstraint":32,"./constraints/PointToPointConstraint":33,"./equations/ContactEquation":35,"./equations/Equation":36,"./equations/FrictionEquation":37,"./equations/RotationalEquation":38,"./equations/RotationalMotorEquation":39,"./material/ContactMaterial":40,"./material/Material":41,"./math/Mat3":43,"./math/Quaternion":44,"./math/Transform":45,"./math/Vec3":46,"./objects/Body":47,"./objects/RaycastVehicle":48,"./objects/RigidVehicle":49,"./objects/SPHSystem":50,"./objects/Spring":51,"./shapes/Box":53,"./shapes/ConvexPolyhedron":54,"./shapes/Cylinder":55,"./shapes/Heightfield":56,"./shapes/Particle":57,"./shapes/Plane":58,"./shapes/Shape":59,"./shapes/Sphere":60,"./shapes/Trimesh":61,"./solver/GSSolver":62,"./solver/Solver":63,"./solver/SplitSolver":64,"./utils/EventTarget":65,"./utils/Pool":67,"./utils/Vec3Pool":70,"./world/Narrowphase":71,"./world/World":72}],18:[function(require,module,exports){
  1537. var Vec3 = require('../math/Vec3');
  1538. var Utils = require('../utils/Utils');
  1539. module.exports = AABB;
  1540. /**
  1541. * Axis aligned bounding box class.
  1542. * @class AABB
  1543. * @constructor
  1544. * @param {Object} [options]
  1545. * @param {Vec3} [options.upperBound]
  1546. * @param {Vec3} [options.lowerBound]
  1547. */
  1548. function AABB(options){
  1549. options = options || {};
  1550. /**
  1551. * The lower bound of the bounding box.
  1552. * @property lowerBound
  1553. * @type {Vec3}
  1554. */
  1555. this.lowerBound = new Vec3();
  1556. if(options.lowerBound){
  1557. this.lowerBound.copy(options.lowerBound);
  1558. }
  1559. /**
  1560. * The upper bound of the bounding box.
  1561. * @property upperBound
  1562. * @type {Vec3}
  1563. */
  1564. this.upperBound = new Vec3();
  1565. if(options.upperBound){
  1566. this.upperBound.copy(options.upperBound);
  1567. }
  1568. }
  1569. var tmp = new Vec3();
  1570. /**
  1571. * Set the AABB bounds from a set of points.
  1572. * @method setFromPoints
  1573. * @param {Array} points An array of Vec3's.
  1574. * @param {Vec3} position
  1575. * @param {Quaternion} quaternion
  1576. * @param {number} skinSize
  1577. * @return {AABB} The self object
  1578. */
  1579. AABB.prototype.setFromPoints = function(points, position, quaternion, skinSize){
  1580. var l = this.lowerBound,
  1581. u = this.upperBound,
  1582. q = quaternion;
  1583. // Set to the first point
  1584. l.copy(points[0]);
  1585. if(q){
  1586. q.vmult(l, l);
  1587. }
  1588. u.copy(l);
  1589. for(var i = 1; i<points.length; i++){
  1590. var p = points[i];
  1591. if(q){
  1592. q.vmult(p, tmp);
  1593. p = tmp;
  1594. }
  1595. if(p.x > u.x){ u.x = p.x; }
  1596. if(p.x < l.x){ l.x = p.x; }
  1597. if(p.y > u.y){ u.y = p.y; }
  1598. if(p.y < l.y){ l.y = p.y; }
  1599. if(p.z > u.z){ u.z = p.z; }
  1600. if(p.z < l.z){ l.z = p.z; }
  1601. }
  1602. // Add offset
  1603. if (position) {
  1604. position.vadd(l, l);
  1605. position.vadd(u, u);
  1606. }
  1607. if(skinSize){
  1608. l.x -= skinSize;
  1609. l.y -= skinSize;
  1610. l.z -= skinSize;
  1611. u.x += skinSize;
  1612. u.y += skinSize;
  1613. u.z += skinSize;
  1614. }
  1615. return this;
  1616. };
  1617. /**
  1618. * Copy bounds from an AABB to this AABB
  1619. * @method copy
  1620. * @param {AABB} aabb Source to copy from
  1621. * @return {AABB} The this object, for chainability
  1622. */
  1623. AABB.prototype.copy = function(aabb){
  1624. this.lowerBound.copy(aabb.lowerBound);
  1625. this.upperBound.copy(aabb.upperBound);
  1626. return this;
  1627. };
  1628. /**
  1629. * Clone an AABB
  1630. * @method clone
  1631. */
  1632. AABB.prototype.clone = function(){
  1633. return new AABB().copy(this);
  1634. };
  1635. /**
  1636. * Extend this AABB so that it covers the given AABB too.
  1637. * @method extend
  1638. * @param {AABB} aabb
  1639. */
  1640. AABB.prototype.extend = function(aabb){
  1641. this.lowerBound.x = Math.min(this.lowerBound.x, aabb.lowerBound.x);
  1642. this.upperBound.x = Math.max(this.upperBound.x, aabb.upperBound.x);
  1643. this.lowerBound.y = Math.min(this.lowerBound.y, aabb.lowerBound.y);
  1644. this.upperBound.y = Math.max(this.upperBound.y, aabb.upperBound.y);
  1645. this.lowerBound.z = Math.min(this.lowerBound.z, aabb.lowerBound.z);
  1646. this.upperBound.z = Math.max(this.upperBound.z, aabb.upperBound.z);
  1647. };
  1648. /**
  1649. * Returns true if the given AABB overlaps this AABB.
  1650. * @method overlaps
  1651. * @param {AABB} aabb
  1652. * @return {Boolean}
  1653. */
  1654. AABB.prototype.overlaps = function(aabb){
  1655. var l1 = this.lowerBound,
  1656. u1 = this.upperBound,
  1657. l2 = aabb.lowerBound,
  1658. u2 = aabb.upperBound;
  1659. // l2 u2
  1660. // |---------|
  1661. // |--------|
  1662. // l1 u1
  1663. var overlapsX = ((l2.x <= u1.x && u1.x <= u2.x) || (l1.x <= u2.x && u2.x <= u1.x));
  1664. var overlapsY = ((l2.y <= u1.y && u1.y <= u2.y) || (l1.y <= u2.y && u2.y <= u1.y));
  1665. var overlapsZ = ((l2.z <= u1.z && u1.z <= u2.z) || (l1.z <= u2.z && u2.z <= u1.z));
  1666. return overlapsX && overlapsY && overlapsZ;
  1667. };
  1668. // Mostly for debugging
  1669. AABB.prototype.volume = function(){
  1670. var l = this.lowerBound,
  1671. u = this.upperBound;
  1672. return (u.x - l.x) * (u.y - l.y) * (u.z - l.z);
  1673. };
  1674. /**
  1675. * Returns true if the given AABB is fully contained in this AABB.
  1676. * @method contains
  1677. * @param {AABB} aabb
  1678. * @return {Boolean}
  1679. */
  1680. AABB.prototype.contains = function(aabb){
  1681. var l1 = this.lowerBound,
  1682. u1 = this.upperBound,
  1683. l2 = aabb.lowerBound,
  1684. u2 = aabb.upperBound;
  1685. // l2 u2
  1686. // |---------|
  1687. // |---------------|
  1688. // l1 u1
  1689. return (
  1690. (l1.x <= l2.x && u1.x >= u2.x) &&
  1691. (l1.y <= l2.y && u1.y >= u2.y) &&
  1692. (l1.z <= l2.z && u1.z >= u2.z)
  1693. );
  1694. };
  1695. /**
  1696. * @method getCorners
  1697. * @param {Vec3} a
  1698. * @param {Vec3} b
  1699. * @param {Vec3} c
  1700. * @param {Vec3} d
  1701. * @param {Vec3} e
  1702. * @param {Vec3} f
  1703. * @param {Vec3} g
  1704. * @param {Vec3} h
  1705. */
  1706. AABB.prototype.getCorners = function(a, b, c, d, e, f, g, h){
  1707. var l = this.lowerBound,
  1708. u = this.upperBound;
  1709. a.copy(l);
  1710. b.set( u.x, l.y, l.z );
  1711. c.set( u.x, u.y, l.z );
  1712. d.set( l.x, u.y, u.z );
  1713. e.set( u.x, l.y, l.z );
  1714. f.set( l.x, u.y, l.z );
  1715. g.set( l.x, l.y, u.z );
  1716. h.copy(u);
  1717. };
  1718. var transformIntoFrame_corners = [
  1719. new Vec3(),
  1720. new Vec3(),
  1721. new Vec3(),
  1722. new Vec3(),
  1723. new Vec3(),
  1724. new Vec3(),
  1725. new Vec3(),
  1726. new Vec3()
  1727. ];
  1728. /**
  1729. * Get the representation of an AABB in another frame.
  1730. * @method toLocalFrame
  1731. * @param {Transform} frame
  1732. * @param {AABB} target
  1733. * @return {AABB} The "target" AABB object.
  1734. */
  1735. AABB.prototype.toLocalFrame = function(frame, target){
  1736. var corners = transformIntoFrame_corners;
  1737. var a = corners[0];
  1738. var b = corners[1];
  1739. var c = corners[2];
  1740. var d = corners[3];
  1741. var e = corners[4];
  1742. var f = corners[5];
  1743. var g = corners[6];
  1744. var h = corners[7];
  1745. // Get corners in current frame
  1746. this.getCorners(a, b, c, d, e, f, g, h);
  1747. // Transform them to new local frame
  1748. for(var i=0; i !== 8; i++){
  1749. var corner = corners[i];
  1750. frame.pointToLocal(corner, corner);
  1751. }
  1752. return target.setFromPoints(corners);
  1753. };
  1754. /**
  1755. * Get the representation of an AABB in the global frame.
  1756. * @method toWorldFrame
  1757. * @param {Transform} frame
  1758. * @param {AABB} target
  1759. * @return {AABB} The "target" AABB object.
  1760. */
  1761. AABB.prototype.toWorldFrame = function(frame, target){
  1762. var corners = transformIntoFrame_corners;
  1763. var a = corners[0];
  1764. var b = corners[1];
  1765. var c = corners[2];
  1766. var d = corners[3];
  1767. var e = corners[4];
  1768. var f = corners[5];
  1769. var g = corners[6];
  1770. var h = corners[7];
  1771. // Get corners in current frame
  1772. this.getCorners(a, b, c, d, e, f, g, h);
  1773. // Transform them to new local frame
  1774. for(var i=0; i !== 8; i++){
  1775. var corner = corners[i];
  1776. frame.pointToWorld(corner, corner);
  1777. }
  1778. return target.setFromPoints(corners);
  1779. };
  1780. /**
  1781. * Check if the AABB is hit by a ray.
  1782. * @param {Ray} ray
  1783. * @return {number}
  1784. */
  1785. AABB.prototype.overlapsRay = function(ray){
  1786. var t = 0;
  1787. // ray.direction is unit direction vector of ray
  1788. var dirFracX = 1 / ray._direction.x;
  1789. var dirFracY = 1 / ray._direction.y;
  1790. var dirFracZ = 1 / ray._direction.z;
  1791. // this.lowerBound is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
  1792. var t1 = (this.lowerBound.x - ray.from.x) * dirFracX;
  1793. var t2 = (this.upperBound.x - ray.from.x) * dirFracX;
  1794. var t3 = (this.lowerBound.y - ray.from.y) * dirFracY;
  1795. var t4 = (this.upperBound.y - ray.from.y) * dirFracY;
  1796. var t5 = (this.lowerBound.z - ray.from.z) * dirFracZ;
  1797. var t6 = (this.upperBound.z - ray.from.z) * dirFracZ;
  1798. // var tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)));
  1799. // var tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)));
  1800. var tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)), Math.min(t5, t6));
  1801. var tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)), Math.max(t5, t6));
  1802. // if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us
  1803. if (tmax < 0){
  1804. //t = tmax;
  1805. return false;
  1806. }
  1807. // if tmin > tmax, ray doesn't intersect AABB
  1808. if (tmin > tmax){
  1809. //t = tmax;
  1810. return false;
  1811. }
  1812. return true;
  1813. };
  1814. },{"../math/Vec3":46,"../utils/Utils":69}],19:[function(require,module,exports){
  1815. module.exports = ArrayCollisionMatrix;
  1816. /**
  1817. * Collision "matrix". It's actually a triangular-shaped array of whether two bodies are touching this step, for reference next step
  1818. * @class ArrayCollisionMatrix
  1819. * @constructor
  1820. */
  1821. function ArrayCollisionMatrix() {
  1822. /**
  1823. * The matrix storage
  1824. * @property matrix
  1825. * @type {Array}
  1826. */
  1827. this.matrix = [];
  1828. }
  1829. /**
  1830. * Get an element
  1831. * @method get
  1832. * @param {Number} i
  1833. * @param {Number} j
  1834. * @return {Number}
  1835. */
  1836. ArrayCollisionMatrix.prototype.get = function(i, j) {
  1837. i = i.index;
  1838. j = j.index;
  1839. if (j > i) {
  1840. var temp = j;
  1841. j = i;
  1842. i = temp;
  1843. }
  1844. return this.matrix[(i*(i + 1)>>1) + j-1];
  1845. };
  1846. /**
  1847. * Set an element
  1848. * @method set
  1849. * @param {Number} i
  1850. * @param {Number} j
  1851. * @param {Number} value
  1852. */
  1853. ArrayCollisionMatrix.prototype.set = function(i, j, value) {
  1854. i = i.index;
  1855. j = j.index;
  1856. if (j > i) {
  1857. var temp = j;
  1858. j = i;
  1859. i = temp;
  1860. }
  1861. this.matrix[(i*(i + 1)>>1) + j-1] = value ? 1 : 0;
  1862. };
  1863. /**
  1864. * Sets all elements to zero
  1865. * @method reset
  1866. */
  1867. ArrayCollisionMatrix.prototype.reset = function() {
  1868. for (var i=0, l=this.matrix.length; i!==l; i++) {
  1869. this.matrix[i]=0;
  1870. }
  1871. };
  1872. /**
  1873. * Sets the max number of objects
  1874. * @method setNumObjects
  1875. * @param {Number} n
  1876. */
  1877. ArrayCollisionMatrix.prototype.setNumObjects = function(n) {
  1878. this.matrix.length = n*(n-1)>>1;
  1879. };
  1880. },{}],20:[function(require,module,exports){
  1881. var Body = require('../objects/Body');
  1882. var Vec3 = require('../math/Vec3');
  1883. var Quaternion = require('../math/Quaternion');
  1884. var Shape = require('../shapes/Shape');
  1885. var Plane = require('../shapes/Plane');
  1886. module.exports = Broadphase;
  1887. /**
  1888. * Base class for broadphase implementations
  1889. * @class Broadphase
  1890. * @constructor
  1891. * @author schteppe
  1892. */
  1893. function Broadphase(){
  1894. /**
  1895. * The world to search for collisions in.
  1896. * @property world
  1897. * @type {World}
  1898. */
  1899. this.world = null;
  1900. /**
  1901. * If set to true, the broadphase uses bounding boxes for intersection test, else it uses bounding spheres.
  1902. * @property useBoundingBoxes
  1903. * @type {Boolean}
  1904. */
  1905. this.useBoundingBoxes = false;
  1906. /**
  1907. * Set to true if the objects in the world moved.
  1908. * @property {Boolean} dirty
  1909. */
  1910. this.dirty = true;
  1911. }
  1912. /**
  1913. * Get the collision pairs from the world
  1914. * @method collisionPairs
  1915. * @param {World} world The world to search in
  1916. * @param {Array} p1 Empty array to be filled with body objects
  1917. * @param {Array} p2 Empty array to be filled with body objects
  1918. */
  1919. Broadphase.prototype.collisionPairs = function(world,p1,p2){
  1920. throw new Error("collisionPairs not implemented for this BroadPhase class!");
  1921. };
  1922. /**
  1923. * Check if a body pair needs to be intersection tested at all.
  1924. * @method needBroadphaseCollision
  1925. * @param {Body} bodyA
  1926. * @param {Body} bodyB
  1927. * @return {bool}
  1928. */
  1929. Broadphase.prototype.needBroadphaseCollision = function(bodyA,bodyB){
  1930. // Check collision filter masks
  1931. if( (bodyA.collisionFilterGroup & bodyB.collisionFilterMask)===0 || (bodyB.collisionFilterGroup & bodyA.collisionFilterMask)===0){
  1932. return false;
  1933. }
  1934. // Check types
  1935. if(((bodyA.type & Body.STATIC)!==0 || bodyA.sleepState === Body.SLEEPING) &&
  1936. ((bodyB.type & Body.STATIC)!==0 || bodyB.sleepState === Body.SLEEPING)) {
  1937. // Both bodies are static or sleeping. Skip.
  1938. return false;
  1939. }
  1940. return true;
  1941. };
  1942. /**
  1943. * Check if the bounding volumes of two bodies intersect.
  1944. * @method intersectionTest
  1945. * @param {Body} bodyA
  1946. * @param {Body} bodyB
  1947. * @param {array} pairs1
  1948. * @param {array} pairs2
  1949. */
  1950. Broadphase.prototype.intersectionTest = function(bodyA, bodyB, pairs1, pairs2){
  1951. if(this.useBoundingBoxes){
  1952. this.doBoundingBoxBroadphase(bodyA,bodyB,pairs1,pairs2);
  1953. } else {
  1954. this.doBoundingSphereBroadphase(bodyA,bodyB,pairs1,pairs2);
  1955. }
  1956. };
  1957. /**
  1958. * Check if the bounding spheres of two bodies are intersecting.
  1959. * @method doBoundingSphereBroadphase
  1960. * @param {Body} bodyA
  1961. * @param {Body} bodyB
  1962. * @param {Array} pairs1 bodyA is appended to this array if intersection
  1963. * @param {Array} pairs2 bodyB is appended to this array if intersection
  1964. */
  1965. var Broadphase_collisionPairs_r = new Vec3(), // Temp objects
  1966. Broadphase_collisionPairs_normal = new Vec3(),
  1967. Broadphase_collisionPairs_quat = new Quaternion(),
  1968. Broadphase_collisionPairs_relpos = new Vec3();
  1969. Broadphase.prototype.doBoundingSphereBroadphase = function(bodyA,bodyB,pairs1,pairs2){
  1970. var r = Broadphase_collisionPairs_r;
  1971. bodyB.position.vsub(bodyA.position,r);
  1972. var boundingRadiusSum2 = Math.pow(bodyA.boundingRadius + bodyB.boundingRadius, 2);
  1973. var norm2 = r.norm2();
  1974. if(norm2 < boundingRadiusSum2){
  1975. pairs1.push(bodyA);
  1976. pairs2.push(bodyB);
  1977. }
  1978. };
  1979. /**
  1980. * Check if the bounding boxes of two bodies are intersecting.
  1981. * @method doBoundingBoxBroadphase
  1982. * @param {Body} bodyA
  1983. * @param {Body} bodyB
  1984. * @param {Array} pairs1
  1985. * @param {Array} pairs2
  1986. */
  1987. Broadphase.prototype.doBoundingBoxBroadphase = function(bodyA,bodyB,pairs1,pairs2){
  1988. if(bodyA.aabbNeedsUpdate){
  1989. bodyA.computeAABB();
  1990. }
  1991. if(bodyB.aabbNeedsUpdate){
  1992. bodyB.computeAABB();
  1993. }
  1994. // Check AABB / AABB
  1995. if(bodyA.aabb.overlaps(bodyB.aabb)){
  1996. pairs1.push(bodyA);
  1997. pairs2.push(bodyB);
  1998. }
  1999. };
  2000. /**
  2001. * Removes duplicate pairs from the pair arrays.
  2002. * @method makePairsUnique
  2003. * @param {Array} pairs1
  2004. * @param {Array} pairs2
  2005. */
  2006. var Broadphase_makePairsUnique_temp = { keys:[] },
  2007. Broadphase_makePairsUnique_p1 = [],
  2008. Broadphase_makePairsUnique_p2 = [];
  2009. Broadphase.prototype.makePairsUnique = function(pairs1,pairs2){
  2010. var t = Broadphase_makePairsUnique_temp,
  2011. p1 = Broadphase_makePairsUnique_p1,
  2012. p2 = Broadphase_makePairsUnique_p2,
  2013. N = pairs1.length;
  2014. for(var i=0; i!==N; i++){
  2015. p1[i] = pairs1[i];
  2016. p2[i] = pairs2[i];
  2017. }
  2018. pairs1.length = 0;
  2019. pairs2.length = 0;
  2020. for(var i=0; i!==N; i++){
  2021. var id1 = p1[i].id,
  2022. id2 = p2[i].id;
  2023. var key = id1 < id2 ? id1+","+id2 : id2+","+id1;
  2024. t[key] = i;
  2025. t.keys.push(key);
  2026. }
  2027. for(var i=0; i!==t.keys.length; i++){
  2028. var key = t.keys.pop(),
  2029. pairIndex = t[key];
  2030. pairs1.push(p1[pairIndex]);
  2031. pairs2.push(p2[pairIndex]);
  2032. delete t[key];
  2033. }
  2034. };
  2035. /**
  2036. * To be implemented by subcasses
  2037. * @method setWorld
  2038. * @param {World} world
  2039. */
  2040. Broadphase.prototype.setWorld = function(world){
  2041. };
  2042. /**
  2043. * Check if the bounding spheres of two bodies overlap.
  2044. * @method boundingSphereCheck
  2045. * @param {Body} bodyA
  2046. * @param {Body} bodyB
  2047. * @return {boolean}
  2048. */
  2049. var bsc_dist = new Vec3();
  2050. Broadphase.boundingSphereCheck = function(bodyA,bodyB){
  2051. var dist = bsc_dist;
  2052. bodyA.position.vsub(bodyB.position,dist);
  2053. return Math.pow(bodyA.shape.boundingSphereRadius + bodyB.shape.boundingSphereRadius,2) > dist.norm2();
  2054. };
  2055. /**
  2056. * Returns all the bodies within the AABB.
  2057. * @method aabbQuery
  2058. * @param {World} world
  2059. * @param {AABB} aabb
  2060. * @param {array} result An array to store resulting bodies in.
  2061. * @return {array}
  2062. */
  2063. Broadphase.prototype.aabbQuery = function(world, aabb, result){
  2064. console.warn('.aabbQuery is not implemented in this Broadphase subclass.');
  2065. return [];
  2066. };
  2067. },{"../math/Quaternion":44,"../math/Vec3":46,"../objects/Body":47,"../shapes/Plane":58,"../shapes/Shape":59}],21:[function(require,module,exports){
  2068. module.exports = GridBroadphase;
  2069. var Broadphase = require('./Broadphase');
  2070. var Vec3 = require('../math/Vec3');
  2071. var Shape = require('../shapes/Shape');
  2072. /**
  2073. * Axis aligned uniform grid broadphase.
  2074. * @class GridBroadphase
  2075. * @constructor
  2076. * @extends Broadphase
  2077. * @todo Needs support for more than just planes and spheres.
  2078. * @param {Vec3} aabbMin
  2079. * @param {Vec3} aabbMax
  2080. * @param {Number} nx Number of boxes along x
  2081. * @param {Number} ny Number of boxes along y
  2082. * @param {Number} nz Number of boxes along z
  2083. */
  2084. function GridBroadphase(aabbMin,aabbMax,nx,ny,nz){
  2085. Broadphase.apply(this);
  2086. this.nx = nx || 10;
  2087. this.ny = ny || 10;
  2088. this.nz = nz || 10;
  2089. this.aabbMin = aabbMin || new Vec3(100,100,100);
  2090. this.aabbMax = aabbMax || new Vec3(-100,-100,-100);
  2091. var nbins = this.nx * this.ny * this.nz;
  2092. if (nbins <= 0) {
  2093. throw "GridBroadphase: Each dimension's n must be >0";
  2094. }
  2095. this.bins = [];
  2096. this.binLengths = []; //Rather than continually resizing arrays (thrashing the memory), just record length and allow them to grow
  2097. this.bins.length = nbins;
  2098. this.binLengths.length = nbins;
  2099. for (var i=0;i<nbins;i++) {
  2100. this.bins[i]=[];
  2101. this.binLengths[i]=0;
  2102. }
  2103. }
  2104. GridBroadphase.prototype = new Broadphase();
  2105. GridBroadphase.prototype.constructor = GridBroadphase;
  2106. /**
  2107. * Get all the collision pairs in the physics world
  2108. * @method collisionPairs
  2109. * @param {World} world
  2110. * @param {Array} pairs1
  2111. * @param {Array} pairs2
  2112. */
  2113. var GridBroadphase_collisionPairs_d = new Vec3();
  2114. var GridBroadphase_collisionPairs_binPos = new Vec3();
  2115. GridBroadphase.prototype.collisionPairs = function(world,pairs1,pairs2){
  2116. var N = world.numObjects(),
  2117. bodies = world.bodies;
  2118. var max = this.aabbMax,
  2119. min = this.aabbMin,
  2120. nx = this.nx,
  2121. ny = this.ny,
  2122. nz = this.nz;
  2123. var xstep = ny*nz;
  2124. var ystep = nz;
  2125. var zstep = 1;
  2126. var xmax = max.x,
  2127. ymax = max.y,
  2128. zmax = max.z,
  2129. xmin = min.x,
  2130. ymin = min.y,
  2131. zmin = min.z;
  2132. var xmult = nx / (xmax-xmin),
  2133. ymult = ny / (ymax-ymin),
  2134. zmult = nz / (zmax-zmin);
  2135. var binsizeX = (xmax - xmin) / nx,
  2136. binsizeY = (ymax - ymin) / ny,
  2137. binsizeZ = (zmax - zmin) / nz;
  2138. var binRadius = Math.sqrt(binsizeX*binsizeX + binsizeY*binsizeY + binsizeZ*binsizeZ) * 0.5;
  2139. var types = Shape.types;
  2140. var SPHERE = types.SPHERE,
  2141. PLANE = types.PLANE,
  2142. BOX = types.BOX,
  2143. COMPOUND = types.COMPOUND,
  2144. CONVEXPOLYHEDRON = types.CONVEXPOLYHEDRON;
  2145. var bins=this.bins,
  2146. binLengths=this.binLengths,
  2147. Nbins=this.bins.length;
  2148. // Reset bins
  2149. for(var i=0; i!==Nbins; i++){
  2150. binLengths[i] = 0;
  2151. }
  2152. var ceil = Math.ceil;
  2153. var min = Math.min;
  2154. var max = Math.max;
  2155. function addBoxToBins(x0,y0,z0,x1,y1,z1,bi) {
  2156. var xoff0 = ((x0 - xmin) * xmult)|0,
  2157. yoff0 = ((y0 - ymin) * ymult)|0,
  2158. zoff0 = ((z0 - zmin) * zmult)|0,
  2159. xoff1 = ceil((x1 - xmin) * xmult),
  2160. yoff1 = ceil((y1 - ymin) * ymult),
  2161. zoff1 = ceil((z1 - zmin) * zmult);
  2162. if (xoff0 < 0) { xoff0 = 0; } else if (xoff0 >= nx) { xoff0 = nx - 1; }
  2163. if (yoff0 < 0) { yoff0 = 0; } else if (yoff0 >= ny) { yoff0 = ny - 1; }
  2164. if (zoff0 < 0) { zoff0 = 0; } else if (zoff0 >= nz) { zoff0 = nz - 1; }
  2165. if (xoff1 < 0) { xoff1 = 0; } else if (xoff1 >= nx) { xoff1 = nx - 1; }
  2166. if (yoff1 < 0) { yoff1 = 0; } else if (yoff1 >= ny) { yoff1 = ny - 1; }
  2167. if (zoff1 < 0) { zoff1 = 0; } else if (zoff1 >= nz) { zoff1 = nz - 1; }
  2168. xoff0 *= xstep;
  2169. yoff0 *= ystep;
  2170. zoff0 *= zstep;
  2171. xoff1 *= xstep;
  2172. yoff1 *= ystep;
  2173. zoff1 *= zstep;
  2174. for (var xoff = xoff0; xoff <= xoff1; xoff += xstep) {
  2175. for (var yoff = yoff0; yoff <= yoff1; yoff += ystep) {
  2176. for (var zoff = zoff0; zoff <= zoff1; zoff += zstep) {
  2177. var idx = xoff+yoff+zoff;
  2178. bins[idx][binLengths[idx]++] = bi;
  2179. }
  2180. }
  2181. }
  2182. }
  2183. // Put all bodies into the bins
  2184. for(var i=0; i!==N; i++){
  2185. var bi = bodies[i];
  2186. var si = bi.shape;
  2187. switch(si.type){
  2188. case SPHERE:
  2189. // Put in bin
  2190. // check if overlap with other bins
  2191. var x = bi.position.x,
  2192. y = bi.position.y,
  2193. z = bi.position.z;
  2194. var r = si.radius;
  2195. addBoxToBins(x-r, y-r, z-r, x+r, y+r, z+r, bi);
  2196. break;
  2197. case PLANE:
  2198. if(si.worldNormalNeedsUpdate){
  2199. si.computeWorldNormal(bi.quaternion);
  2200. }
  2201. var planeNormal = si.worldNormal;
  2202. //Relative position from origin of plane object to the first bin
  2203. //Incremented as we iterate through the bins
  2204. var xreset = xmin + binsizeX*0.5 - bi.position.x,
  2205. yreset = ymin + binsizeY*0.5 - bi.position.y,
  2206. zreset = zmin + binsizeZ*0.5 - bi.position.z;
  2207. var d = GridBroadphase_collisionPairs_d;
  2208. d.set(xreset, yreset, zreset);
  2209. for (var xi = 0, xoff = 0; xi !== nx; xi++, xoff += xstep, d.y = yreset, d.x += binsizeX) {
  2210. for (var yi = 0, yoff = 0; yi !== ny; yi++, yoff += ystep, d.z = zreset, d.y += binsizeY) {
  2211. for (var zi = 0, zoff = 0; zi !== nz; zi++, zoff += zstep, d.z += binsizeZ) {
  2212. if (d.dot(planeNormal) < binRadius) {
  2213. var idx = xoff + yoff + zoff;
  2214. bins[idx][binLengths[idx]++] = bi;
  2215. }
  2216. }
  2217. }
  2218. }
  2219. break;
  2220. default:
  2221. if (bi.aabbNeedsUpdate) {
  2222. bi.computeAABB();
  2223. }
  2224. addBoxToBins(
  2225. bi.aabb.lowerBound.x,
  2226. bi.aabb.lowerBound.y,
  2227. bi.aabb.lowerBound.z,
  2228. bi.aabb.upperBound.x,
  2229. bi.aabb.upperBound.y,
  2230. bi.aabb.upperBound.z,
  2231. bi);
  2232. break;
  2233. }
  2234. }
  2235. // Check each bin
  2236. for(var i=0; i!==Nbins; i++){
  2237. var binLength = binLengths[i];
  2238. //Skip bins with no potential collisions
  2239. if (binLength > 1) {
  2240. var bin = bins[i];
  2241. // Do N^2 broadphase inside
  2242. for(var xi=0; xi!==binLength; xi++){
  2243. var bi = bin[xi];
  2244. for(var yi=0; yi!==xi; yi++){
  2245. var bj = bin[yi];
  2246. if(this.needBroadphaseCollision(bi,bj)){
  2247. this.intersectionTest(bi,bj,pairs1,pairs2);
  2248. }
  2249. }
  2250. }
  2251. }
  2252. }
  2253. // for (var zi = 0, zoff=0; zi < nz; zi++, zoff+= zstep) {
  2254. // console.log("layer "+zi);
  2255. // for (var yi = 0, yoff=0; yi < ny; yi++, yoff += ystep) {
  2256. // var row = '';
  2257. // for (var xi = 0, xoff=0; xi < nx; xi++, xoff += xstep) {
  2258. // var idx = xoff + yoff + zoff;
  2259. // row += ' ' + binLengths[idx];
  2260. // }
  2261. // console.log(row);
  2262. // }
  2263. // }
  2264. this.makePairsUnique(pairs1,pairs2);
  2265. };
  2266. },{"../math/Vec3":46,"../shapes/Shape":59,"./Broadphase":20}],22:[function(require,module,exports){
  2267. module.exports = NaiveBroadphase;
  2268. var Broadphase = require('./Broadphase');
  2269. var AABB = require('./AABB');
  2270. /**
  2271. * Naive broadphase implementation, used in lack of better ones.
  2272. * @class NaiveBroadphase
  2273. * @constructor
  2274. * @description The naive broadphase looks at all possible pairs without restriction, therefore it has complexity N^2 (which is bad)
  2275. * @extends Broadphase
  2276. */
  2277. function NaiveBroadphase(){
  2278. Broadphase.apply(this);
  2279. }
  2280. NaiveBroadphase.prototype = new Broadphase();
  2281. NaiveBroadphase.prototype.constructor = NaiveBroadphase;
  2282. /**
  2283. * Get all the collision pairs in the physics world
  2284. * @method collisionPairs
  2285. * @param {World} world
  2286. * @param {Array} pairs1
  2287. * @param {Array} pairs2
  2288. */
  2289. NaiveBroadphase.prototype.collisionPairs = function(world,pairs1,pairs2){
  2290. var bodies = world.bodies,
  2291. n = bodies.length,
  2292. i,j,bi,bj;
  2293. // Naive N^2 ftw!
  2294. for(i=0; i!==n; i++){
  2295. for(j=0; j!==i; j++){
  2296. bi = bodies[i];
  2297. bj = bodies[j];
  2298. if(!this.needBroadphaseCollision(bi,bj)){
  2299. continue;
  2300. }
  2301. this.intersectionTest(bi,bj,pairs1,pairs2);
  2302. }
  2303. }
  2304. };
  2305. var tmpAABB = new AABB();
  2306. /**
  2307. * Returns all the bodies within an AABB.
  2308. * @method aabbQuery
  2309. * @param {World} world
  2310. * @param {AABB} aabb
  2311. * @param {array} result An array to store resulting bodies in.
  2312. * @return {array}
  2313. */
  2314. NaiveBroadphase.prototype.aabbQuery = function(world, aabb, result){
  2315. result = result || [];
  2316. for(var i = 0; i < world.bodies.length; i++){
  2317. var b = world.bodies[i];
  2318. if(b.aabbNeedsUpdate){
  2319. b.computeAABB();
  2320. }
  2321. // Ugly hack until Body gets aabb
  2322. if(b.aabb.overlaps(aabb)){
  2323. result.push(b);
  2324. }
  2325. }
  2326. return result;
  2327. };
  2328. },{"./AABB":18,"./Broadphase":20}],23:[function(require,module,exports){
  2329. module.exports = ObjectCollisionMatrix;
  2330. /**
  2331. * Records what objects are colliding with each other
  2332. * @class ObjectCollisionMatrix
  2333. * @constructor
  2334. */
  2335. function ObjectCollisionMatrix() {
  2336. /**
  2337. * The matrix storage
  2338. * @property matrix
  2339. * @type {Object}
  2340. */
  2341. this.matrix = {};
  2342. }
  2343. /**
  2344. * @method get
  2345. * @param {Number} i
  2346. * @param {Number} j
  2347. * @return {Number}
  2348. */
  2349. ObjectCollisionMatrix.prototype.get = function(i, j) {
  2350. i = i.id;
  2351. j = j.id;
  2352. if (j > i) {
  2353. var temp = j;
  2354. j = i;
  2355. i = temp;
  2356. }
  2357. return i+'-'+j in this.matrix;
  2358. };
  2359. /**
  2360. * @method set
  2361. * @param {Number} i
  2362. * @param {Number} j
  2363. * @param {Number} value
  2364. */
  2365. ObjectCollisionMatrix.prototype.set = function(i, j, value) {
  2366. i = i.id;
  2367. j = j.id;
  2368. if (j > i) {
  2369. var temp = j;
  2370. j = i;
  2371. i = temp;
  2372. }
  2373. if (value) {
  2374. this.matrix[i+'-'+j] = true;
  2375. }
  2376. else {
  2377. delete this.matrix[i+'-'+j];
  2378. }
  2379. };
  2380. /**
  2381. * Empty the matrix
  2382. * @method reset
  2383. */
  2384. ObjectCollisionMatrix.prototype.reset = function() {
  2385. this.matrix = {};
  2386. };
  2387. /**
  2388. * Set max number of objects
  2389. * @method setNumObjects
  2390. * @param {Number} n
  2391. */
  2392. ObjectCollisionMatrix.prototype.setNumObjects = function(n) {
  2393. };
  2394. },{}],24:[function(require,module,exports){
  2395. module.exports = OverlapKeeper;
  2396. /**
  2397. * @class OverlapKeeper
  2398. * @constructor
  2399. */
  2400. function OverlapKeeper() {
  2401. this.current = [];
  2402. this.previous = [];
  2403. }
  2404. OverlapKeeper.prototype.getKey = function(i, j) {
  2405. if (j < i) {
  2406. var temp = j;
  2407. j = i;
  2408. i = temp;
  2409. }
  2410. return (i << 16) | j;
  2411. };
  2412. /**
  2413. * @method set
  2414. * @param {Number} i
  2415. * @param {Number} j
  2416. */
  2417. OverlapKeeper.prototype.set = function(i, j) {
  2418. // Insertion sort. This way the diff will have linear complexity.
  2419. var key = this.getKey(i, j);
  2420. var current = this.current;
  2421. var index = 0;
  2422. while(key > current[index]){
  2423. index++;
  2424. }
  2425. if(key === current[index]){
  2426. return; // Pair was already added
  2427. }
  2428. for(var j=current.length-1; j>=index; j--){
  2429. current[j + 1] = current[j];
  2430. }
  2431. current[index] = key;
  2432. };
  2433. /**
  2434. * @method tick
  2435. */
  2436. OverlapKeeper.prototype.tick = function() {
  2437. var tmp = this.current;
  2438. this.current = this.previous;
  2439. this.previous = tmp;
  2440. this.current.length = 0;
  2441. };
  2442. function unpackAndPush(array, key){
  2443. array.push((key & 0xFFFF0000) >> 16, key & 0x0000FFFF);
  2444. }
  2445. /**
  2446. * @method getDiff
  2447. * @param {array} additions
  2448. * @param {array} removals
  2449. */
  2450. OverlapKeeper.prototype.getDiff = function(additions, removals) {
  2451. var a = this.current;
  2452. var b = this.previous;
  2453. var al = a.length;
  2454. var bl = b.length;
  2455. var j=0;
  2456. for (var i = 0; i < al; i++) {
  2457. var found = false;
  2458. var keyA = a[i];
  2459. while(keyA > b[j]){
  2460. j++;
  2461. }
  2462. found = keyA === b[j];
  2463. if(!found){
  2464. unpackAndPush(additions, keyA);
  2465. }
  2466. }
  2467. j = 0;
  2468. for (var i = 0; i < bl; i++) {
  2469. var found = false;
  2470. var keyB = b[i];
  2471. while(keyB > a[j]){
  2472. j++;
  2473. }
  2474. found = a[j] === keyB;
  2475. if(!found){
  2476. unpackAndPush(removals, keyB);
  2477. }
  2478. }
  2479. };
  2480. },{}],25:[function(require,module,exports){
  2481. module.exports = Ray;
  2482. var Vec3 = require('../math/Vec3');
  2483. var Quaternion = require('../math/Quaternion');
  2484. var Transform = require('../math/Transform');
  2485. var ConvexPolyhedron = require('../shapes/ConvexPolyhedron');
  2486. var Box = require('../shapes/Box');
  2487. var RaycastResult = require('../collision/RaycastResult');
  2488. var Shape = require('../shapes/Shape');
  2489. var AABB = require('../collision/AABB');
  2490. /**
  2491. * A line in 3D space that intersects bodies and return points.
  2492. * @class Ray
  2493. * @constructor
  2494. * @param {Vec3} from
  2495. * @param {Vec3} to
  2496. */
  2497. function Ray(from, to){
  2498. /**
  2499. * @property {Vec3} from
  2500. */
  2501. this.from = from ? from.clone() : new Vec3();
  2502. /**
  2503. * @property {Vec3} to
  2504. */
  2505. this.to = to ? to.clone() : new Vec3();
  2506. /**
  2507. * @private
  2508. * @property {Vec3} _direction
  2509. */
  2510. this._direction = new Vec3();
  2511. /**
  2512. * The precision of the ray. Used when checking parallelity etc.
  2513. * @property {Number} precision
  2514. */
  2515. this.precision = 0.0001;
  2516. /**
  2517. * Set to true if you want the Ray to take .collisionResponse flags into account on bodies and shapes.
  2518. * @property {Boolean} checkCollisionResponse
  2519. */
  2520. this.checkCollisionResponse = true;
  2521. /**
  2522. * If set to true, the ray skips any hits with normal.dot(rayDirection) < 0.
  2523. * @property {Boolean} skipBackfaces
  2524. */
  2525. this.skipBackfaces = false;
  2526. /**
  2527. * @property {number} collisionFilterMask
  2528. * @default -1
  2529. */
  2530. this.collisionFilterMask = -1;
  2531. /**
  2532. * @property {number} collisionFilterGroup
  2533. * @default -1
  2534. */
  2535. this.collisionFilterGroup = -1;
  2536. /**
  2537. * The intersection mode. Should be Ray.ANY, Ray.ALL or Ray.CLOSEST.
  2538. * @property {number} mode
  2539. */
  2540. this.mode = Ray.ANY;
  2541. /**
  2542. * Current result object.
  2543. * @property {RaycastResult} result
  2544. */
  2545. this.result = new RaycastResult();
  2546. /**
  2547. * Will be set to true during intersectWorld() if the ray hit anything.
  2548. * @property {Boolean} hasHit
  2549. */
  2550. this.hasHit = false;
  2551. /**
  2552. * Current, user-provided result callback. Will be used if mode is Ray.ALL.
  2553. * @property {Function} callback
  2554. */
  2555. this.callback = function(result){};
  2556. }
  2557. Ray.prototype.constructor = Ray;
  2558. Ray.CLOSEST = 1;
  2559. Ray.ANY = 2;
  2560. Ray.ALL = 4;
  2561. var tmpAABB = new AABB();
  2562. var tmpArray = [];
  2563. /**
  2564. * Do itersection against all bodies in the given World.
  2565. * @method intersectWorld
  2566. * @param {World} world
  2567. * @param {object} options
  2568. * @return {Boolean} True if the ray hit anything, otherwise false.
  2569. */
  2570. Ray.prototype.intersectWorld = function (world, options) {
  2571. this.mode = options.mode || Ray.ANY;
  2572. this.result = options.result || new RaycastResult();
  2573. this.skipBackfaces = !!options.skipBackfaces;
  2574. this.collisionFilterMask = typeof(options.collisionFilterMask) !== 'undefined' ? options.collisionFilterMask : -1;
  2575. this.collisionFilterGroup = typeof(options.collisionFilterGroup) !== 'undefined' ? options.collisionFilterGroup : -1;
  2576. if(options.from){
  2577. this.from.copy(options.from);
  2578. }
  2579. if(options.to){
  2580. this.to.copy(options.to);
  2581. }
  2582. this.callback = options.callback || function(){};
  2583. this.hasHit = false;
  2584. this.result.reset();
  2585. this._updateDirection();
  2586. this.getAABB(tmpAABB);
  2587. tmpArray.length = 0;
  2588. world.broadphase.aabbQuery(world, tmpAABB, tmpArray);
  2589. this.intersectBodies(tmpArray);
  2590. return this.hasHit;
  2591. };
  2592. var v1 = new Vec3(),
  2593. v2 = new Vec3();
  2594. /*
  2595. * As per "Barycentric Technique" as named here http://www.blackpawn.com/texts/pointinpoly/default.html But without the division
  2596. */
  2597. Ray.pointInTriangle = pointInTriangle;
  2598. function pointInTriangle(p, a, b, c) {
  2599. c.vsub(a,v0);
  2600. b.vsub(a,v1);
  2601. p.vsub(a,v2);
  2602. var dot00 = v0.dot( v0 );
  2603. var dot01 = v0.dot( v1 );
  2604. var dot02 = v0.dot( v2 );
  2605. var dot11 = v1.dot( v1 );
  2606. var dot12 = v1.dot( v2 );
  2607. var u,v;
  2608. return ( (u = dot11 * dot02 - dot01 * dot12) >= 0 ) &&
  2609. ( (v = dot00 * dot12 - dot01 * dot02) >= 0 ) &&
  2610. ( u + v < ( dot00 * dot11 - dot01 * dot01 ) );
  2611. }
  2612. /**
  2613. * Shoot a ray at a body, get back information about the hit.
  2614. * @method intersectBody
  2615. * @private
  2616. * @param {Body} body
  2617. * @param {RaycastResult} [result] Deprecated - set the result property of the Ray instead.
  2618. */
  2619. var intersectBody_xi = new Vec3();
  2620. var intersectBody_qi = new Quaternion();
  2621. Ray.prototype.intersectBody = function (body, result) {
  2622. if(result){
  2623. this.result = result;
  2624. this._updateDirection();
  2625. }
  2626. var checkCollisionResponse = this.checkCollisionResponse;
  2627. if(checkCollisionResponse && !body.collisionResponse){
  2628. return;
  2629. }
  2630. if((this.collisionFilterGroup & body.collisionFilterMask)===0 || (body.collisionFilterGroup & this.collisionFilterMask)===0){
  2631. return;
  2632. }
  2633. var xi = intersectBody_xi;
  2634. var qi = intersectBody_qi;
  2635. for (var i = 0, N = body.shapes.length; i < N; i++) {
  2636. var shape = body.shapes[i];
  2637. if(checkCollisionResponse && !shape.collisionResponse){
  2638. continue; // Skip
  2639. }
  2640. body.quaternion.mult(body.shapeOrientations[i], qi);
  2641. body.quaternion.vmult(body.shapeOffsets[i], xi);
  2642. xi.vadd(body.position, xi);
  2643. this.intersectShape(
  2644. shape,
  2645. qi,
  2646. xi,
  2647. body
  2648. );
  2649. if(this.result._shouldStop){
  2650. break;
  2651. }
  2652. }
  2653. };
  2654. /**
  2655. * @method intersectBodies
  2656. * @param {Array} bodies An array of Body objects.
  2657. * @param {RaycastResult} [result] Deprecated
  2658. */
  2659. Ray.prototype.intersectBodies = function (bodies, result) {
  2660. if(result){
  2661. this.result = result;
  2662. this._updateDirection();
  2663. }
  2664. for ( var i = 0, l = bodies.length; !this.result._shouldStop && i < l; i ++ ) {
  2665. this.intersectBody(bodies[i]);
  2666. }
  2667. };
  2668. /**
  2669. * Updates the _direction vector.
  2670. * @private
  2671. * @method _updateDirection
  2672. */
  2673. Ray.prototype._updateDirection = function(){
  2674. this.to.vsub(this.from, this._direction);
  2675. this._direction.normalize();
  2676. };
  2677. /**
  2678. * @method intersectShape
  2679. * @private
  2680. * @param {Shape} shape
  2681. * @param {Quaternion} quat
  2682. * @param {Vec3} position
  2683. * @param {Body} body
  2684. */
  2685. Ray.prototype.intersectShape = function(shape, quat, position, body){
  2686. var from = this.from;
  2687. // Checking boundingSphere
  2688. var distance = distanceFromIntersection(from, this._direction, position);
  2689. if ( distance > shape.boundingSphereRadius ) {
  2690. return;
  2691. }
  2692. var intersectMethod = this[shape.type];
  2693. if(intersectMethod){
  2694. intersectMethod.call(this, shape, quat, position, body, shape);
  2695. }
  2696. };
  2697. var vector = new Vec3();
  2698. var normal = new Vec3();
  2699. var intersectPoint = new Vec3();
  2700. var a = new Vec3();
  2701. var b = new Vec3();
  2702. var c = new Vec3();
  2703. var d = new Vec3();
  2704. var tmpRaycastResult = new RaycastResult();
  2705. /**
  2706. * @method intersectBox
  2707. * @private
  2708. * @param {Shape} shape
  2709. * @param {Quaternion} quat
  2710. * @param {Vec3} position
  2711. * @param {Body} body
  2712. */
  2713. Ray.prototype.intersectBox = function(shape, quat, position, body, reportedShape){
  2714. return this.intersectConvex(shape.convexPolyhedronRepresentation, quat, position, body, reportedShape);
  2715. };
  2716. Ray.prototype[Shape.types.BOX] = Ray.prototype.intersectBox;
  2717. /**
  2718. * @method intersectPlane
  2719. * @private
  2720. * @param {Shape} shape
  2721. * @param {Quaternion} quat
  2722. * @param {Vec3} position
  2723. * @param {Body} body
  2724. */
  2725. Ray.prototype.intersectPlane = function(shape, quat, position, body, reportedShape){
  2726. var from = this.from;
  2727. var to = this.to;
  2728. var direction = this._direction;
  2729. // Get plane normal
  2730. var worldNormal = new Vec3(0, 0, 1);
  2731. quat.vmult(worldNormal, worldNormal);
  2732. var len = new Vec3();
  2733. from.vsub(position, len);
  2734. var planeToFrom = len.dot(worldNormal);
  2735. to.vsub(position, len);
  2736. var planeToTo = len.dot(worldNormal);
  2737. if(planeToFrom * planeToTo > 0){
  2738. // "from" and "to" are on the same side of the plane... bail out
  2739. return;
  2740. }
  2741. if(from.distanceTo(to) < planeToFrom){
  2742. return;
  2743. }
  2744. var n_dot_dir = worldNormal.dot(direction);
  2745. if (Math.abs(n_dot_dir) < this.precision) {
  2746. // No intersection
  2747. return;
  2748. }
  2749. var planePointToFrom = new Vec3();
  2750. var dir_scaled_with_t = new Vec3();
  2751. var hitPointWorld = new Vec3();
  2752. from.vsub(position, planePointToFrom);
  2753. var t = -worldNormal.dot(planePointToFrom) / n_dot_dir;
  2754. direction.scale(t, dir_scaled_with_t);
  2755. from.vadd(dir_scaled_with_t, hitPointWorld);
  2756. this.reportIntersection(worldNormal, hitPointWorld, reportedShape, body, -1);
  2757. };
  2758. Ray.prototype[Shape.types.PLANE] = Ray.prototype.intersectPlane;
  2759. /**
  2760. * Get the world AABB of the ray.
  2761. * @method getAABB
  2762. * @param {AABB} aabb
  2763. */
  2764. Ray.prototype.getAABB = function(result){
  2765. var to = this.to;
  2766. var from = this.from;
  2767. result.lowerBound.x = Math.min(to.x, from.x);
  2768. result.lowerBound.y = Math.min(to.y, from.y);
  2769. result.lowerBound.z = Math.min(to.z, from.z);
  2770. result.upperBound.x = Math.max(to.x, from.x);
  2771. result.upperBound.y = Math.max(to.y, from.y);
  2772. result.upperBound.z = Math.max(to.z, from.z);
  2773. };
  2774. var intersectConvexOptions = {
  2775. faceList: [0]
  2776. };
  2777. var worldPillarOffset = new Vec3();
  2778. var intersectHeightfield_localRay = new Ray();
  2779. var intersectHeightfield_index = [];
  2780. var intersectHeightfield_minMax = [];
  2781. /**
  2782. * @method intersectHeightfield
  2783. * @private
  2784. * @param {Shape} shape
  2785. * @param {Quaternion} quat
  2786. * @param {Vec3} position
  2787. * @param {Body} body
  2788. */
  2789. Ray.prototype.intersectHeightfield = function(shape, quat, position, body, reportedShape){
  2790. var data = shape.data,
  2791. w = shape.elementSize;
  2792. // Convert the ray to local heightfield coordinates
  2793. var localRay = intersectHeightfield_localRay; //new Ray(this.from, this.to);
  2794. localRay.from.copy(this.from);
  2795. localRay.to.copy(this.to);
  2796. Transform.pointToLocalFrame(position, quat, localRay.from, localRay.from);
  2797. Transform.pointToLocalFrame(position, quat, localRay.to, localRay.to);
  2798. localRay._updateDirection();
  2799. // Get the index of the data points to test against
  2800. var index = intersectHeightfield_index;
  2801. var iMinX, iMinY, iMaxX, iMaxY;
  2802. // Set to max
  2803. iMinX = iMinY = 0;
  2804. iMaxX = iMaxY = shape.data.length - 1;
  2805. var aabb = new AABB();
  2806. localRay.getAABB(aabb);
  2807. shape.getIndexOfPosition(aabb.lowerBound.x, aabb.lowerBound.y, index, true);
  2808. iMinX = Math.max(iMinX, index[0]);
  2809. iMinY = Math.max(iMinY, index[1]);
  2810. shape.getIndexOfPosition(aabb.upperBound.x, aabb.upperBound.y, index, true);
  2811. iMaxX = Math.min(iMaxX, index[0] + 1);
  2812. iMaxY = Math.min(iMaxY, index[1] + 1);
  2813. for(var i = iMinX; i < iMaxX; i++){
  2814. for(var j = iMinY; j < iMaxY; j++){
  2815. if(this.result._shouldStop){
  2816. return;
  2817. }
  2818. shape.getAabbAtIndex(i, j, aabb);
  2819. if(!aabb.overlapsRay(localRay)){
  2820. continue;
  2821. }
  2822. // Lower triangle
  2823. shape.getConvexTrianglePillar(i, j, false);
  2824. Transform.pointToWorldFrame(position, quat, shape.pillarOffset, worldPillarOffset);
  2825. this.intersectConvex(shape.pillarConvex, quat, worldPillarOffset, body, reportedShape, intersectConvexOptions);
  2826. if(this.result._shouldStop){
  2827. return;
  2828. }
  2829. // Upper triangle
  2830. shape.getConvexTrianglePillar(i, j, true);
  2831. Transform.pointToWorldFrame(position, quat, shape.pillarOffset, worldPillarOffset);
  2832. this.intersectConvex(shape.pillarConvex, quat, worldPillarOffset, body, reportedShape, intersectConvexOptions);
  2833. }
  2834. }
  2835. };
  2836. Ray.prototype[Shape.types.HEIGHTFIELD] = Ray.prototype.intersectHeightfield;
  2837. var Ray_intersectSphere_intersectionPoint = new Vec3();
  2838. var Ray_intersectSphere_normal = new Vec3();
  2839. /**
  2840. * @method intersectSphere
  2841. * @private
  2842. * @param {Shape} shape
  2843. * @param {Quaternion} quat
  2844. * @param {Vec3} position
  2845. * @param {Body} body
  2846. */
  2847. Ray.prototype.intersectSphere = function(shape, quat, position, body, reportedShape){
  2848. var from = this.from,
  2849. to = this.to,
  2850. r = shape.radius;
  2851. var a = Math.pow(to.x - from.x, 2) + Math.pow(to.y - from.y, 2) + Math.pow(to.z - from.z, 2);
  2852. var 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));
  2853. var c = Math.pow(from.x - position.x, 2) + Math.pow(from.y - position.y, 2) + Math.pow(from.z - position.z, 2) - Math.pow(r, 2);
  2854. var delta = Math.pow(b, 2) - 4 * a * c;
  2855. var intersectionPoint = Ray_intersectSphere_intersectionPoint;
  2856. var normal = Ray_intersectSphere_normal;
  2857. if(delta < 0){
  2858. // No intersection
  2859. return;
  2860. } else if(delta === 0){
  2861. // single intersection point
  2862. from.lerp(to, delta, intersectionPoint);
  2863. intersectionPoint.vsub(position, normal);
  2864. normal.normalize();
  2865. this.reportIntersection(normal, intersectionPoint, reportedShape, body, -1);
  2866. } else {
  2867. var d1 = (- b - Math.sqrt(delta)) / (2 * a);
  2868. var d2 = (- b + Math.sqrt(delta)) / (2 * a);
  2869. if(d1 >= 0 && d1 <= 1){
  2870. from.lerp(to, d1, intersectionPoint);
  2871. intersectionPoint.vsub(position, normal);
  2872. normal.normalize();
  2873. this.reportIntersection(normal, intersectionPoint, reportedShape, body, -1);
  2874. }
  2875. if(this.result._shouldStop){
  2876. return;
  2877. }
  2878. if(d2 >= 0 && d2 <= 1){
  2879. from.lerp(to, d2, intersectionPoint);
  2880. intersectionPoint.vsub(position, normal);
  2881. normal.normalize();
  2882. this.reportIntersection(normal, intersectionPoint, reportedShape, body, -1);
  2883. }
  2884. }
  2885. };
  2886. Ray.prototype[Shape.types.SPHERE] = Ray.prototype.intersectSphere;
  2887. var intersectConvex_normal = new Vec3();
  2888. var intersectConvex_minDistNormal = new Vec3();
  2889. var intersectConvex_minDistIntersect = new Vec3();
  2890. var intersectConvex_vector = new Vec3();
  2891. /**
  2892. * @method intersectConvex
  2893. * @private
  2894. * @param {Shape} shape
  2895. * @param {Quaternion} quat
  2896. * @param {Vec3} position
  2897. * @param {Body} body
  2898. * @param {object} [options]
  2899. * @param {array} [options.faceList]
  2900. */
  2901. Ray.prototype.intersectConvex = function intersectConvex(
  2902. shape,
  2903. quat,
  2904. position,
  2905. body,
  2906. reportedShape,
  2907. options
  2908. ){
  2909. var minDistNormal = intersectConvex_minDistNormal;
  2910. var normal = intersectConvex_normal;
  2911. var vector = intersectConvex_vector;
  2912. var minDistIntersect = intersectConvex_minDistIntersect;
  2913. var faceList = (options && options.faceList) || null;
  2914. // Checking faces
  2915. var faces = shape.faces,
  2916. vertices = shape.vertices,
  2917. normals = shape.faceNormals;
  2918. var direction = this._direction;
  2919. var from = this.from;
  2920. var to = this.to;
  2921. var fromToDistance = from.distanceTo(to);
  2922. var minDist = -1;
  2923. var Nfaces = faceList ? faceList.length : faces.length;
  2924. var result = this.result;
  2925. for (var j = 0; !result._shouldStop && j < Nfaces; j++) {
  2926. var fi = faceList ? faceList[j] : j;
  2927. var face = faces[fi];
  2928. var faceNormal = normals[fi];
  2929. var q = quat;
  2930. var x = position;
  2931. // determine if ray intersects the plane of the face
  2932. // note: this works regardless of the direction of the face normal
  2933. // Get plane point in world coordinates...
  2934. vector.copy(vertices[face[0]]);
  2935. q.vmult(vector,vector);
  2936. vector.vadd(x,vector);
  2937. // ...but make it relative to the ray from. We'll fix this later.
  2938. vector.vsub(from,vector);
  2939. // Get plane normal
  2940. q.vmult(faceNormal,normal);
  2941. // If this dot product is negative, we have something interesting
  2942. var dot = direction.dot(normal);
  2943. // Bail out if ray and plane are parallel
  2944. if ( Math.abs( dot ) < this.precision ){
  2945. continue;
  2946. }
  2947. // calc distance to plane
  2948. var scalar = normal.dot(vector) / dot;
  2949. // if negative distance, then plane is behind ray
  2950. if (scalar < 0){
  2951. continue;
  2952. }
  2953. // if (dot < 0) {
  2954. // Intersection point is from + direction * scalar
  2955. direction.mult(scalar,intersectPoint);
  2956. intersectPoint.vadd(from,intersectPoint);
  2957. // a is the point we compare points b and c with.
  2958. a.copy(vertices[face[0]]);
  2959. q.vmult(a,a);
  2960. x.vadd(a,a);
  2961. for(var i = 1; !result._shouldStop && i < face.length - 1; i++){
  2962. // Transform 3 vertices to world coords
  2963. b.copy(vertices[face[i]]);
  2964. c.copy(vertices[face[i+1]]);
  2965. q.vmult(b,b);
  2966. q.vmult(c,c);
  2967. x.vadd(b,b);
  2968. x.vadd(c,c);
  2969. var distance = intersectPoint.distanceTo(from);
  2970. if(!(pointInTriangle(intersectPoint, a, b, c) || pointInTriangle(intersectPoint, b, a, c)) || distance > fromToDistance){
  2971. continue;
  2972. }
  2973. this.reportIntersection(normal, intersectPoint, reportedShape, body, fi);
  2974. }
  2975. // }
  2976. }
  2977. };
  2978. Ray.prototype[Shape.types.CONVEXPOLYHEDRON] = Ray.prototype.intersectConvex;
  2979. var intersectTrimesh_normal = new Vec3();
  2980. var intersectTrimesh_localDirection = new Vec3();
  2981. var intersectTrimesh_localFrom = new Vec3();
  2982. var intersectTrimesh_localTo = new Vec3();
  2983. var intersectTrimesh_worldNormal = new Vec3();
  2984. var intersectTrimesh_worldIntersectPoint = new Vec3();
  2985. var intersectTrimesh_localAABB = new AABB();
  2986. var intersectTrimesh_triangles = [];
  2987. var intersectTrimesh_treeTransform = new Transform();
  2988. /**
  2989. * @method intersectTrimesh
  2990. * @private
  2991. * @param {Shape} shape
  2992. * @param {Quaternion} quat
  2993. * @param {Vec3} position
  2994. * @param {Body} body
  2995. * @param {object} [options]
  2996. * @todo Optimize by transforming the world to local space first.
  2997. * @todo Use Octree lookup
  2998. */
  2999. Ray.prototype.intersectTrimesh = function intersectTrimesh(
  3000. mesh,
  3001. quat,
  3002. position,
  3003. body,
  3004. reportedShape,
  3005. options
  3006. ){
  3007. var normal = intersectTrimesh_normal;
  3008. var triangles = intersectTrimesh_triangles;
  3009. var treeTransform = intersectTrimesh_treeTransform;
  3010. var minDistNormal = intersectConvex_minDistNormal;
  3011. var vector = intersectConvex_vector;
  3012. var minDistIntersect = intersectConvex_minDistIntersect;
  3013. var localAABB = intersectTrimesh_localAABB;
  3014. var localDirection = intersectTrimesh_localDirection;
  3015. var localFrom = intersectTrimesh_localFrom;
  3016. var localTo = intersectTrimesh_localTo;
  3017. var worldIntersectPoint = intersectTrimesh_worldIntersectPoint;
  3018. var worldNormal = intersectTrimesh_worldNormal;
  3019. var faceList = (options && options.faceList) || null;
  3020. // Checking faces
  3021. var indices = mesh.indices,
  3022. vertices = mesh.vertices,
  3023. normals = mesh.faceNormals;
  3024. var from = this.from;
  3025. var to = this.to;
  3026. var direction = this._direction;
  3027. var minDist = -1;
  3028. treeTransform.position.copy(position);
  3029. treeTransform.quaternion.copy(quat);
  3030. // Transform ray to local space!
  3031. Transform.vectorToLocalFrame(position, quat, direction, localDirection);
  3032. Transform.pointToLocalFrame(position, quat, from, localFrom);
  3033. Transform.pointToLocalFrame(position, quat, to, localTo);
  3034. localTo.x *= mesh.scale.x;
  3035. localTo.y *= mesh.scale.y;
  3036. localTo.z *= mesh.scale.z;
  3037. localFrom.x *= mesh.scale.x;
  3038. localFrom.y *= mesh.scale.y;
  3039. localFrom.z *= mesh.scale.z;
  3040. localTo.vsub(localFrom, localDirection);
  3041. localDirection.normalize();
  3042. var fromToDistanceSquared = localFrom.distanceSquared(localTo);
  3043. mesh.tree.rayQuery(this, treeTransform, triangles);
  3044. for (var i = 0, N = triangles.length; !this.result._shouldStop && i !== N; i++) {
  3045. var trianglesIndex = triangles[i];
  3046. mesh.getNormal(trianglesIndex, normal);
  3047. // determine if ray intersects the plane of the face
  3048. // note: this works regardless of the direction of the face normal
  3049. // Get plane point in world coordinates...
  3050. mesh.getVertex(indices[trianglesIndex * 3], a);
  3051. // ...but make it relative to the ray from. We'll fix this later.
  3052. a.vsub(localFrom,vector);
  3053. // If this dot product is negative, we have something interesting
  3054. var dot = localDirection.dot(normal);
  3055. // Bail out if ray and plane are parallel
  3056. // if (Math.abs( dot ) < this.precision){
  3057. // continue;
  3058. // }
  3059. // calc distance to plane
  3060. var scalar = normal.dot(vector) / dot;
  3061. // if negative distance, then plane is behind ray
  3062. if (scalar < 0){
  3063. continue;
  3064. }
  3065. // Intersection point is from + direction * scalar
  3066. localDirection.scale(scalar,intersectPoint);
  3067. intersectPoint.vadd(localFrom,intersectPoint);
  3068. // Get triangle vertices
  3069. mesh.getVertex(indices[trianglesIndex * 3 + 1], b);
  3070. mesh.getVertex(indices[trianglesIndex * 3 + 2], c);
  3071. var squaredDistance = intersectPoint.distanceSquared(localFrom);
  3072. if(!(pointInTriangle(intersectPoint, b, a, c) || pointInTriangle(intersectPoint, a, b, c)) || squaredDistance > fromToDistanceSquared){
  3073. continue;
  3074. }
  3075. // transform intersectpoint and normal to world
  3076. Transform.vectorToWorldFrame(quat, normal, worldNormal);
  3077. Transform.pointToWorldFrame(position, quat, intersectPoint, worldIntersectPoint);
  3078. this.reportIntersection(worldNormal, worldIntersectPoint, reportedShape, body, trianglesIndex);
  3079. }
  3080. triangles.length = 0;
  3081. };
  3082. Ray.prototype[Shape.types.TRIMESH] = Ray.prototype.intersectTrimesh;
  3083. /**
  3084. * @method reportIntersection
  3085. * @private
  3086. * @param {Vec3} normal
  3087. * @param {Vec3} hitPointWorld
  3088. * @param {Shape} shape
  3089. * @param {Body} body
  3090. * @return {boolean} True if the intersections should continue
  3091. */
  3092. Ray.prototype.reportIntersection = function(normal, hitPointWorld, shape, body, hitFaceIndex){
  3093. var from = this.from;
  3094. var to = this.to;
  3095. var distance = from.distanceTo(hitPointWorld);
  3096. var result = this.result;
  3097. // Skip back faces?
  3098. if(this.skipBackfaces && normal.dot(this._direction) > 0){
  3099. return;
  3100. }
  3101. result.hitFaceIndex = typeof(hitFaceIndex) !== 'undefined' ? hitFaceIndex : -1;
  3102. switch(this.mode){
  3103. case Ray.ALL:
  3104. this.hasHit = true;
  3105. result.set(
  3106. from,
  3107. to,
  3108. normal,
  3109. hitPointWorld,
  3110. shape,
  3111. body,
  3112. distance
  3113. );
  3114. result.hasHit = true;
  3115. this.callback(result);
  3116. break;
  3117. case Ray.CLOSEST:
  3118. // Store if closer than current closest
  3119. if(distance < result.distance || !result.hasHit){
  3120. this.hasHit = true;
  3121. result.hasHit = true;
  3122. result.set(
  3123. from,
  3124. to,
  3125. normal,
  3126. hitPointWorld,
  3127. shape,
  3128. body,
  3129. distance
  3130. );
  3131. }
  3132. break;
  3133. case Ray.ANY:
  3134. // Report and stop.
  3135. this.hasHit = true;
  3136. result.hasHit = true;
  3137. result.set(
  3138. from,
  3139. to,
  3140. normal,
  3141. hitPointWorld,
  3142. shape,
  3143. body,
  3144. distance
  3145. );
  3146. result._shouldStop = true;
  3147. break;
  3148. }
  3149. };
  3150. var v0 = new Vec3(),
  3151. intersect = new Vec3();
  3152. function distanceFromIntersection(from, direction, position) {
  3153. // v0 is vector from from to position
  3154. position.vsub(from,v0);
  3155. var dot = v0.dot(direction);
  3156. // intersect = direction*dot + from
  3157. direction.mult(dot,intersect);
  3158. intersect.vadd(from,intersect);
  3159. var distance = position.distanceTo(intersect);
  3160. return distance;
  3161. }
  3162. },{"../collision/AABB":18,"../collision/RaycastResult":26,"../math/Quaternion":44,"../math/Transform":45,"../math/Vec3":46,"../shapes/Box":53,"../shapes/ConvexPolyhedron":54,"../shapes/Shape":59}],26:[function(require,module,exports){
  3163. var Vec3 = require('../math/Vec3');
  3164. module.exports = RaycastResult;
  3165. /**
  3166. * Storage for Ray casting data.
  3167. * @class RaycastResult
  3168. * @constructor
  3169. */
  3170. function RaycastResult(){
  3171. /**
  3172. * @property {Vec3} rayFromWorld
  3173. */
  3174. this.rayFromWorld = new Vec3();
  3175. /**
  3176. * @property {Vec3} rayToWorld
  3177. */
  3178. this.rayToWorld = new Vec3();
  3179. /**
  3180. * @property {Vec3} hitNormalWorld
  3181. */
  3182. this.hitNormalWorld = new Vec3();
  3183. /**
  3184. * @property {Vec3} hitPointWorld
  3185. */
  3186. this.hitPointWorld = new Vec3();
  3187. /**
  3188. * @property {boolean} hasHit
  3189. */
  3190. this.hasHit = false;
  3191. /**
  3192. * The hit shape, or null.
  3193. * @property {Shape} shape
  3194. */
  3195. this.shape = null;
  3196. /**
  3197. * The hit body, or null.
  3198. * @property {Body} body
  3199. */
  3200. this.body = null;
  3201. /**
  3202. * The index of the hit triangle, if the hit shape was a trimesh.
  3203. * @property {number} hitFaceIndex
  3204. * @default -1
  3205. */
  3206. this.hitFaceIndex = -1;
  3207. /**
  3208. * Distance to the hit. Will be set to -1 if there was no hit.
  3209. * @property {number} distance
  3210. * @default -1
  3211. */
  3212. this.distance = -1;
  3213. /**
  3214. * If the ray should stop traversing the bodies.
  3215. * @private
  3216. * @property {Boolean} _shouldStop
  3217. * @default false
  3218. */
  3219. this._shouldStop = false;
  3220. }
  3221. /**
  3222. * Reset all result data.
  3223. * @method reset
  3224. */
  3225. RaycastResult.prototype.reset = function () {
  3226. this.rayFromWorld.setZero();
  3227. this.rayToWorld.setZero();
  3228. this.hitNormalWorld.setZero();
  3229. this.hitPointWorld.setZero();
  3230. this.hasHit = false;
  3231. this.shape = null;
  3232. this.body = null;
  3233. this.hitFaceIndex = -1;
  3234. this.distance = -1;
  3235. this._shouldStop = false;
  3236. };
  3237. /**
  3238. * @method abort
  3239. */
  3240. RaycastResult.prototype.abort = function(){
  3241. this._shouldStop = true;
  3242. };
  3243. /**
  3244. * @method set
  3245. * @param {Vec3} rayFromWorld
  3246. * @param {Vec3} rayToWorld
  3247. * @param {Vec3} hitNormalWorld
  3248. * @param {Vec3} hitPointWorld
  3249. * @param {Shape} shape
  3250. * @param {Body} body
  3251. * @param {number} distance
  3252. */
  3253. RaycastResult.prototype.set = function(
  3254. rayFromWorld,
  3255. rayToWorld,
  3256. hitNormalWorld,
  3257. hitPointWorld,
  3258. shape,
  3259. body,
  3260. distance
  3261. ){
  3262. this.rayFromWorld.copy(rayFromWorld);
  3263. this.rayToWorld.copy(rayToWorld);
  3264. this.hitNormalWorld.copy(hitNormalWorld);
  3265. this.hitPointWorld.copy(hitPointWorld);
  3266. this.shape = shape;
  3267. this.body = body;
  3268. this.distance = distance;
  3269. };
  3270. },{"../math/Vec3":46}],27:[function(require,module,exports){
  3271. var Shape = require('../shapes/Shape');
  3272. var Broadphase = require('../collision/Broadphase');
  3273. module.exports = SAPBroadphase;
  3274. /**
  3275. * Sweep and prune broadphase along one axis.
  3276. *
  3277. * @class SAPBroadphase
  3278. * @constructor
  3279. * @param {World} [world]
  3280. * @extends Broadphase
  3281. */
  3282. function SAPBroadphase(world){
  3283. Broadphase.apply(this);
  3284. /**
  3285. * List of bodies currently in the broadphase.
  3286. * @property axisList
  3287. * @type {Array}
  3288. */
  3289. this.axisList = [];
  3290. /**
  3291. * The world to search in.
  3292. * @property world
  3293. * @type {World}
  3294. */
  3295. this.world = null;
  3296. /**
  3297. * Axis to sort the bodies along. Set to 0 for x axis, and 1 for y axis. For best performance, choose an axis that the bodies are spread out more on.
  3298. * @property axisIndex
  3299. * @type {Number}
  3300. */
  3301. this.axisIndex = 0;
  3302. var axisList = this.axisList;
  3303. this._addBodyHandler = function(e){
  3304. axisList.push(e.body);
  3305. };
  3306. this._removeBodyHandler = function(e){
  3307. var idx = axisList.indexOf(e.body);
  3308. if(idx !== -1){
  3309. axisList.splice(idx,1);
  3310. }
  3311. };
  3312. if(world){
  3313. this.setWorld(world);
  3314. }
  3315. }
  3316. SAPBroadphase.prototype = new Broadphase();
  3317. /**
  3318. * Change the world
  3319. * @method setWorld
  3320. * @param {World} world
  3321. */
  3322. SAPBroadphase.prototype.setWorld = function(world){
  3323. // Clear the old axis array
  3324. this.axisList.length = 0;
  3325. // Add all bodies from the new world
  3326. for(var i=0; i<world.bodies.length; i++){
  3327. this.axisList.push(world.bodies[i]);
  3328. }
  3329. // Remove old handlers, if any
  3330. world.removeEventListener("addBody", this._addBodyHandler);
  3331. world.removeEventListener("removeBody", this._removeBodyHandler);
  3332. // Add handlers to update the list of bodies.
  3333. world.addEventListener("addBody", this._addBodyHandler);
  3334. world.addEventListener("removeBody", this._removeBodyHandler);
  3335. this.world = world;
  3336. this.dirty = true;
  3337. };
  3338. /**
  3339. * @static
  3340. * @method insertionSortX
  3341. * @param {Array} a
  3342. * @return {Array}
  3343. */
  3344. SAPBroadphase.insertionSortX = function(a) {
  3345. for(var i=1,l=a.length;i<l;i++) {
  3346. var v = a[i];
  3347. for(var j=i - 1;j>=0;j--) {
  3348. if(a[j].aabb.lowerBound.x <= v.aabb.lowerBound.x){
  3349. break;
  3350. }
  3351. a[j+1] = a[j];
  3352. }
  3353. a[j+1] = v;
  3354. }
  3355. return a;
  3356. };
  3357. /**
  3358. * @static
  3359. * @method insertionSortY
  3360. * @param {Array} a
  3361. * @return {Array}
  3362. */
  3363. SAPBroadphase.insertionSortY = function(a) {
  3364. for(var i=1,l=a.length;i<l;i++) {
  3365. var v = a[i];
  3366. for(var j=i - 1;j>=0;j--) {
  3367. if(a[j].aabb.lowerBound.y <= v.aabb.lowerBound.y){
  3368. break;
  3369. }
  3370. a[j+1] = a[j];
  3371. }
  3372. a[j+1] = v;
  3373. }
  3374. return a;
  3375. };
  3376. /**
  3377. * @static
  3378. * @method insertionSortZ
  3379. * @param {Array} a
  3380. * @return {Array}
  3381. */
  3382. SAPBroadphase.insertionSortZ = function(a) {
  3383. for(var i=1,l=a.length;i<l;i++) {
  3384. var v = a[i];
  3385. for(var j=i - 1;j>=0;j--) {
  3386. if(a[j].aabb.lowerBound.z <= v.aabb.lowerBound.z){
  3387. break;
  3388. }
  3389. a[j+1] = a[j];
  3390. }
  3391. a[j+1] = v;
  3392. }
  3393. return a;
  3394. };
  3395. /**
  3396. * Collect all collision pairs
  3397. * @method collisionPairs
  3398. * @param {World} world
  3399. * @param {Array} p1
  3400. * @param {Array} p2
  3401. */
  3402. SAPBroadphase.prototype.collisionPairs = function(world,p1,p2){
  3403. var bodies = this.axisList,
  3404. N = bodies.length,
  3405. axisIndex = this.axisIndex,
  3406. i, j;
  3407. if(this.dirty){
  3408. this.sortList();
  3409. this.dirty = false;
  3410. }
  3411. // Look through the list
  3412. for(i=0; i !== N; i++){
  3413. var bi = bodies[i];
  3414. for(j=i+1; j < N; j++){
  3415. var bj = bodies[j];
  3416. if(!this.needBroadphaseCollision(bi,bj)){
  3417. continue;
  3418. }
  3419. if(!SAPBroadphase.checkBounds(bi,bj,axisIndex)){
  3420. break;
  3421. }
  3422. this.intersectionTest(bi,bj,p1,p2);
  3423. }
  3424. }
  3425. };
  3426. SAPBroadphase.prototype.sortList = function(){
  3427. var axisList = this.axisList;
  3428. var axisIndex = this.axisIndex;
  3429. var N = axisList.length;
  3430. // Update AABBs
  3431. for(var i = 0; i!==N; i++){
  3432. var bi = axisList[i];
  3433. if(bi.aabbNeedsUpdate){
  3434. bi.computeAABB();
  3435. }
  3436. }
  3437. // Sort the list
  3438. if(axisIndex === 0){
  3439. SAPBroadphase.insertionSortX(axisList);
  3440. } else if(axisIndex === 1){
  3441. SAPBroadphase.insertionSortY(axisList);
  3442. } else if(axisIndex === 2){
  3443. SAPBroadphase.insertionSortZ(axisList);
  3444. }
  3445. };
  3446. /**
  3447. * Check if the bounds of two bodies overlap, along the given SAP axis.
  3448. * @static
  3449. * @method checkBounds
  3450. * @param {Body} bi
  3451. * @param {Body} bj
  3452. * @param {Number} axisIndex
  3453. * @return {Boolean}
  3454. */
  3455. SAPBroadphase.checkBounds = function(bi, bj, axisIndex){
  3456. var biPos;
  3457. var bjPos;
  3458. if(axisIndex === 0){
  3459. biPos = bi.position.x;
  3460. bjPos = bj.position.x;
  3461. } else if(axisIndex === 1){
  3462. biPos = bi.position.y;
  3463. bjPos = bj.position.y;
  3464. } else if(axisIndex === 2){
  3465. biPos = bi.position.z;
  3466. bjPos = bj.position.z;
  3467. }
  3468. var ri = bi.boundingRadius,
  3469. rj = bj.boundingRadius,
  3470. boundA1 = biPos - ri,
  3471. boundA2 = biPos + ri,
  3472. boundB1 = bjPos - rj,
  3473. boundB2 = bjPos + rj;
  3474. return boundB1 < boundA2;
  3475. };
  3476. /**
  3477. * Computes the variance of the body positions and estimates the best
  3478. * axis to use. Will automatically set property .axisIndex.
  3479. * @method autoDetectAxis
  3480. */
  3481. SAPBroadphase.prototype.autoDetectAxis = function(){
  3482. var sumX=0,
  3483. sumX2=0,
  3484. sumY=0,
  3485. sumY2=0,
  3486. sumZ=0,
  3487. sumZ2=0,
  3488. bodies = this.axisList,
  3489. N = bodies.length,
  3490. invN=1/N;
  3491. for(var i=0; i!==N; i++){
  3492. var b = bodies[i];
  3493. var centerX = b.position.x;
  3494. sumX += centerX;
  3495. sumX2 += centerX*centerX;
  3496. var centerY = b.position.y;
  3497. sumY += centerY;
  3498. sumY2 += centerY*centerY;
  3499. var centerZ = b.position.z;
  3500. sumZ += centerZ;
  3501. sumZ2 += centerZ*centerZ;
  3502. }
  3503. var varianceX = sumX2 - sumX*sumX*invN,
  3504. varianceY = sumY2 - sumY*sumY*invN,
  3505. varianceZ = sumZ2 - sumZ*sumZ*invN;
  3506. if(varianceX > varianceY){
  3507. if(varianceX > varianceZ){
  3508. this.axisIndex = 0;
  3509. } else{
  3510. this.axisIndex = 2;
  3511. }
  3512. } else if(varianceY > varianceZ){
  3513. this.axisIndex = 1;
  3514. } else{
  3515. this.axisIndex = 2;
  3516. }
  3517. };
  3518. /**
  3519. * Returns all the bodies within an AABB.
  3520. * @method aabbQuery
  3521. * @param {World} world
  3522. * @param {AABB} aabb
  3523. * @param {array} result An array to store resulting bodies in.
  3524. * @return {array}
  3525. */
  3526. SAPBroadphase.prototype.aabbQuery = function(world, aabb, result){
  3527. result = result || [];
  3528. if(this.dirty){
  3529. this.sortList();
  3530. this.dirty = false;
  3531. }
  3532. var axisIndex = this.axisIndex, axis = 'x';
  3533. if(axisIndex === 1){ axis = 'y'; }
  3534. if(axisIndex === 2){ axis = 'z'; }
  3535. var axisList = this.axisList;
  3536. var lower = aabb.lowerBound[axis];
  3537. var upper = aabb.upperBound[axis];
  3538. for(var i = 0; i < axisList.length; i++){
  3539. var b = axisList[i];
  3540. if(b.aabbNeedsUpdate){
  3541. b.computeAABB();
  3542. }
  3543. if(b.aabb.overlaps(aabb)){
  3544. result.push(b);
  3545. }
  3546. }
  3547. return result;
  3548. };
  3549. },{"../collision/Broadphase":20,"../shapes/Shape":59}],28:[function(require,module,exports){
  3550. module.exports = ConeTwistConstraint;
  3551. var Constraint = require('./Constraint');
  3552. var PointToPointConstraint = require('./PointToPointConstraint');
  3553. var ConeEquation = require('../equations/ConeEquation');
  3554. var RotationalEquation = require('../equations/RotationalEquation');
  3555. var ContactEquation = require('../equations/ContactEquation');
  3556. var Vec3 = require('../math/Vec3');
  3557. /**
  3558. * @class ConeTwistConstraint
  3559. * @constructor
  3560. * @author schteppe
  3561. * @param {Body} bodyA
  3562. * @param {Body} bodyB
  3563. * @param {object} [options]
  3564. * @param {Vec3} [options.pivotA]
  3565. * @param {Vec3} [options.pivotB]
  3566. * @param {Vec3} [options.axisA]
  3567. * @param {Vec3} [options.axisB]
  3568. * @param {Number} [options.maxForce=1e6]
  3569. * @extends PointToPointConstraint
  3570. */
  3571. function ConeTwistConstraint(bodyA, bodyB, options){
  3572. options = options || {};
  3573. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  3574. // Set pivot point in between
  3575. var pivotA = options.pivotA ? options.pivotA.clone() : new Vec3();
  3576. var pivotB = options.pivotB ? options.pivotB.clone() : new Vec3();
  3577. this.axisA = options.axisA ? options.axisA.clone() : new Vec3();
  3578. this.axisB = options.axisB ? options.axisB.clone() : new Vec3();
  3579. PointToPointConstraint.call(this, bodyA, pivotA, bodyB, pivotB, maxForce);
  3580. this.collideConnected = !!options.collideConnected;
  3581. this.angle = typeof(options.angle) !== 'undefined' ? options.angle : 0;
  3582. /**
  3583. * @property {ConeEquation} coneEquation
  3584. */
  3585. var c = this.coneEquation = new ConeEquation(bodyA,bodyB,options);
  3586. /**
  3587. * @property {RotationalEquation} twistEquation
  3588. */
  3589. var t = this.twistEquation = new RotationalEquation(bodyA,bodyB,options);
  3590. this.twistAngle = typeof(options.twistAngle) !== 'undefined' ? options.twistAngle : 0;
  3591. // Make the cone equation push the bodies toward the cone axis, not outward
  3592. c.maxForce = 0;
  3593. c.minForce = -maxForce;
  3594. // Make the twist equation add torque toward the initial position
  3595. t.maxForce = 0;
  3596. t.minForce = -maxForce;
  3597. this.equations.push(c, t);
  3598. }
  3599. ConeTwistConstraint.prototype = new PointToPointConstraint();
  3600. ConeTwistConstraint.constructor = ConeTwistConstraint;
  3601. var ConeTwistConstraint_update_tmpVec1 = new Vec3();
  3602. var ConeTwistConstraint_update_tmpVec2 = new Vec3();
  3603. ConeTwistConstraint.prototype.update = function(){
  3604. var bodyA = this.bodyA,
  3605. bodyB = this.bodyB,
  3606. cone = this.coneEquation,
  3607. twist = this.twistEquation;
  3608. PointToPointConstraint.prototype.update.call(this);
  3609. // Update the axes to the cone constraint
  3610. bodyA.vectorToWorldFrame(this.axisA, cone.axisA);
  3611. bodyB.vectorToWorldFrame(this.axisB, cone.axisB);
  3612. // Update the world axes in the twist constraint
  3613. this.axisA.tangents(twist.axisA, twist.axisA);
  3614. bodyA.vectorToWorldFrame(twist.axisA, twist.axisA);
  3615. this.axisB.tangents(twist.axisB, twist.axisB);
  3616. bodyB.vectorToWorldFrame(twist.axisB, twist.axisB);
  3617. cone.angle = this.angle;
  3618. twist.maxAngle = this.twistAngle;
  3619. };
  3620. },{"../equations/ConeEquation":34,"../equations/ContactEquation":35,"../equations/RotationalEquation":38,"../math/Vec3":46,"./Constraint":29,"./PointToPointConstraint":33}],29:[function(require,module,exports){
  3621. module.exports = Constraint;
  3622. var Utils = require('../utils/Utils');
  3623. /**
  3624. * Constraint base class
  3625. * @class Constraint
  3626. * @author schteppe
  3627. * @constructor
  3628. * @param {Body} bodyA
  3629. * @param {Body} bodyB
  3630. * @param {object} [options]
  3631. * @param {boolean} [options.collideConnected=true]
  3632. * @param {boolean} [options.wakeUpBodies=true]
  3633. */
  3634. function Constraint(bodyA, bodyB, options){
  3635. options = Utils.defaults(options,{
  3636. collideConnected : true,
  3637. wakeUpBodies : true,
  3638. });
  3639. /**
  3640. * Equations to be solved in this constraint
  3641. * @property equations
  3642. * @type {Array}
  3643. */
  3644. this.equations = [];
  3645. /**
  3646. * @property {Body} bodyA
  3647. */
  3648. this.bodyA = bodyA;
  3649. /**
  3650. * @property {Body} bodyB
  3651. */
  3652. this.bodyB = bodyB;
  3653. /**
  3654. * @property {Number} id
  3655. */
  3656. this.id = Constraint.idCounter++;
  3657. /**
  3658. * Set to true if you want the bodies to collide when they are connected.
  3659. * @property collideConnected
  3660. * @type {boolean}
  3661. */
  3662. this.collideConnected = options.collideConnected;
  3663. if(options.wakeUpBodies){
  3664. if(bodyA){
  3665. bodyA.wakeUp();
  3666. }
  3667. if(bodyB){
  3668. bodyB.wakeUp();
  3669. }
  3670. }
  3671. }
  3672. /**
  3673. * Update all the equations with data.
  3674. * @method update
  3675. */
  3676. Constraint.prototype.update = function(){
  3677. throw new Error("method update() not implmemented in this Constraint subclass!");
  3678. };
  3679. /**
  3680. * Enables all equations in the constraint.
  3681. * @method enable
  3682. */
  3683. Constraint.prototype.enable = function(){
  3684. var eqs = this.equations;
  3685. for(var i=0; i<eqs.length; i++){
  3686. eqs[i].enabled = true;
  3687. }
  3688. };
  3689. /**
  3690. * Disables all equations in the constraint.
  3691. * @method disable
  3692. */
  3693. Constraint.prototype.disable = function(){
  3694. var eqs = this.equations;
  3695. for(var i=0; i<eqs.length; i++){
  3696. eqs[i].enabled = false;
  3697. }
  3698. };
  3699. Constraint.idCounter = 0;
  3700. },{"../utils/Utils":69}],30:[function(require,module,exports){
  3701. module.exports = DistanceConstraint;
  3702. var Constraint = require('./Constraint');
  3703. var ContactEquation = require('../equations/ContactEquation');
  3704. /**
  3705. * Constrains two bodies to be at a constant distance from each others center of mass.
  3706. * @class DistanceConstraint
  3707. * @constructor
  3708. * @author schteppe
  3709. * @param {Body} bodyA
  3710. * @param {Body} bodyB
  3711. * @param {Number} [distance] The distance to keep. If undefined, it will be set to the current distance between bodyA and bodyB
  3712. * @param {Number} [maxForce=1e6]
  3713. * @extends Constraint
  3714. */
  3715. function DistanceConstraint(bodyA,bodyB,distance,maxForce){
  3716. Constraint.call(this,bodyA,bodyB);
  3717. if(typeof(distance)==="undefined") {
  3718. distance = bodyA.position.distanceTo(bodyB.position);
  3719. }
  3720. if(typeof(maxForce)==="undefined") {
  3721. maxForce = 1e6;
  3722. }
  3723. /**
  3724. * @property {number} distance
  3725. */
  3726. this.distance = distance;
  3727. /**
  3728. * @property {ContactEquation} distanceEquation
  3729. */
  3730. var eq = this.distanceEquation = new ContactEquation(bodyA, bodyB);
  3731. this.equations.push(eq);
  3732. // Make it bidirectional
  3733. eq.minForce = -maxForce;
  3734. eq.maxForce = maxForce;
  3735. }
  3736. DistanceConstraint.prototype = new Constraint();
  3737. DistanceConstraint.prototype.update = function(){
  3738. var bodyA = this.bodyA;
  3739. var bodyB = this.bodyB;
  3740. var eq = this.distanceEquation;
  3741. var halfDist = this.distance * 0.5;
  3742. var normal = eq.ni;
  3743. bodyB.position.vsub(bodyA.position, normal);
  3744. normal.normalize();
  3745. normal.mult(halfDist, eq.ri);
  3746. normal.mult(-halfDist, eq.rj);
  3747. };
  3748. },{"../equations/ContactEquation":35,"./Constraint":29}],31:[function(require,module,exports){
  3749. module.exports = HingeConstraint;
  3750. var Constraint = require('./Constraint');
  3751. var PointToPointConstraint = require('./PointToPointConstraint');
  3752. var RotationalEquation = require('../equations/RotationalEquation');
  3753. var RotationalMotorEquation = require('../equations/RotationalMotorEquation');
  3754. var ContactEquation = require('../equations/ContactEquation');
  3755. var Vec3 = require('../math/Vec3');
  3756. /**
  3757. * Hinge constraint. Think of it as a door hinge. It tries to keep the door in the correct place and with the correct orientation.
  3758. * @class HingeConstraint
  3759. * @constructor
  3760. * @author schteppe
  3761. * @param {Body} bodyA
  3762. * @param {Body} bodyB
  3763. * @param {object} [options]
  3764. * @param {Vec3} [options.pivotA] A point defined locally in bodyA. This defines the offset of axisA.
  3765. * @param {Vec3} [options.axisA] An axis that bodyA can rotate around, defined locally in bodyA.
  3766. * @param {Vec3} [options.pivotB]
  3767. * @param {Vec3} [options.axisB]
  3768. * @param {Number} [options.maxForce=1e6]
  3769. * @extends PointToPointConstraint
  3770. */
  3771. function HingeConstraint(bodyA, bodyB, options){
  3772. options = options || {};
  3773. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  3774. var pivotA = options.pivotA ? options.pivotA.clone() : new Vec3();
  3775. var pivotB = options.pivotB ? options.pivotB.clone() : new Vec3();
  3776. PointToPointConstraint.call(this, bodyA, pivotA, bodyB, pivotB, maxForce);
  3777. /**
  3778. * Rotation axis, defined locally in bodyA.
  3779. * @property {Vec3} axisA
  3780. */
  3781. var axisA = this.axisA = options.axisA ? options.axisA.clone() : new Vec3(1,0,0);
  3782. axisA.normalize();
  3783. /**
  3784. * Rotation axis, defined locally in bodyB.
  3785. * @property {Vec3} axisB
  3786. */
  3787. var axisB = this.axisB = options.axisB ? options.axisB.clone() : new Vec3(1,0,0);
  3788. axisB.normalize();
  3789. /**
  3790. * @property {RotationalEquation} rotationalEquation1
  3791. */
  3792. var r1 = this.rotationalEquation1 = new RotationalEquation(bodyA,bodyB,options);
  3793. /**
  3794. * @property {RotationalEquation} rotationalEquation2
  3795. */
  3796. var r2 = this.rotationalEquation2 = new RotationalEquation(bodyA,bodyB,options);
  3797. /**
  3798. * @property {RotationalMotorEquation} motorEquation
  3799. */
  3800. var motor = this.motorEquation = new RotationalMotorEquation(bodyA,bodyB,maxForce);
  3801. motor.enabled = false; // Not enabled by default
  3802. // Equations to be fed to the solver
  3803. this.equations.push(
  3804. r1, // rotational1
  3805. r2, // rotational2
  3806. motor
  3807. );
  3808. }
  3809. HingeConstraint.prototype = new PointToPointConstraint();
  3810. HingeConstraint.constructor = HingeConstraint;
  3811. /**
  3812. * @method enableMotor
  3813. */
  3814. HingeConstraint.prototype.enableMotor = function(){
  3815. this.motorEquation.enabled = true;
  3816. };
  3817. /**
  3818. * @method disableMotor
  3819. */
  3820. HingeConstraint.prototype.disableMotor = function(){
  3821. this.motorEquation.enabled = false;
  3822. };
  3823. /**
  3824. * @method setMotorSpeed
  3825. * @param {number} speed
  3826. */
  3827. HingeConstraint.prototype.setMotorSpeed = function(speed){
  3828. this.motorEquation.targetVelocity = speed;
  3829. };
  3830. /**
  3831. * @method setMotorMaxForce
  3832. * @param {number} maxForce
  3833. */
  3834. HingeConstraint.prototype.setMotorMaxForce = function(maxForce){
  3835. this.motorEquation.maxForce = maxForce;
  3836. this.motorEquation.minForce = -maxForce;
  3837. };
  3838. var HingeConstraint_update_tmpVec1 = new Vec3();
  3839. var HingeConstraint_update_tmpVec2 = new Vec3();
  3840. HingeConstraint.prototype.update = function(){
  3841. var bodyA = this.bodyA,
  3842. bodyB = this.bodyB,
  3843. motor = this.motorEquation,
  3844. r1 = this.rotationalEquation1,
  3845. r2 = this.rotationalEquation2,
  3846. worldAxisA = HingeConstraint_update_tmpVec1,
  3847. worldAxisB = HingeConstraint_update_tmpVec2;
  3848. var axisA = this.axisA;
  3849. var axisB = this.axisB;
  3850. PointToPointConstraint.prototype.update.call(this);
  3851. // Get world axes
  3852. bodyA.quaternion.vmult(axisA, worldAxisA);
  3853. bodyB.quaternion.vmult(axisB, worldAxisB);
  3854. worldAxisA.tangents(r1.axisA, r2.axisA);
  3855. r1.axisB.copy(worldAxisB);
  3856. r2.axisB.copy(worldAxisB);
  3857. if(this.motorEquation.enabled){
  3858. bodyA.quaternion.vmult(this.axisA, motor.axisA);
  3859. bodyB.quaternion.vmult(this.axisB, motor.axisB);
  3860. }
  3861. };
  3862. },{"../equations/ContactEquation":35,"../equations/RotationalEquation":38,"../equations/RotationalMotorEquation":39,"../math/Vec3":46,"./Constraint":29,"./PointToPointConstraint":33}],32:[function(require,module,exports){
  3863. module.exports = LockConstraint;
  3864. var Constraint = require('./Constraint');
  3865. var PointToPointConstraint = require('./PointToPointConstraint');
  3866. var RotationalEquation = require('../equations/RotationalEquation');
  3867. var RotationalMotorEquation = require('../equations/RotationalMotorEquation');
  3868. var ContactEquation = require('../equations/ContactEquation');
  3869. var Vec3 = require('../math/Vec3');
  3870. /**
  3871. * Lock constraint. Will remove all degrees of freedom between the bodies.
  3872. * @class LockConstraint
  3873. * @constructor
  3874. * @author schteppe
  3875. * @param {Body} bodyA
  3876. * @param {Body} bodyB
  3877. * @param {object} [options]
  3878. * @param {Number} [options.maxForce=1e6]
  3879. * @extends PointToPointConstraint
  3880. */
  3881. function LockConstraint(bodyA, bodyB, options){
  3882. options = options || {};
  3883. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  3884. // Set pivot point in between
  3885. var pivotA = new Vec3();
  3886. var pivotB = new Vec3();
  3887. var halfWay = new Vec3();
  3888. bodyA.position.vadd(bodyB.position, halfWay);
  3889. halfWay.scale(0.5, halfWay);
  3890. bodyB.pointToLocalFrame(halfWay, pivotB);
  3891. bodyA.pointToLocalFrame(halfWay, pivotA);
  3892. // The point-to-point constraint will keep a point shared between the bodies
  3893. PointToPointConstraint.call(this, bodyA, pivotA, bodyB, pivotB, maxForce);
  3894. // Store initial rotation of the bodies as unit vectors in the local body spaces
  3895. this.xA = bodyA.vectorToLocalFrame(Vec3.UNIT_X);
  3896. this.xB = bodyB.vectorToLocalFrame(Vec3.UNIT_X);
  3897. this.yA = bodyA.vectorToLocalFrame(Vec3.UNIT_Y);
  3898. this.yB = bodyB.vectorToLocalFrame(Vec3.UNIT_Y);
  3899. this.zA = bodyA.vectorToLocalFrame(Vec3.UNIT_Z);
  3900. this.zB = bodyB.vectorToLocalFrame(Vec3.UNIT_Z);
  3901. // ...and the following rotational equations will keep all rotational DOF's in place
  3902. /**
  3903. * @property {RotationalEquation} rotationalEquation1
  3904. */
  3905. var r1 = this.rotationalEquation1 = new RotationalEquation(bodyA,bodyB,options);
  3906. /**
  3907. * @property {RotationalEquation} rotationalEquation2
  3908. */
  3909. var r2 = this.rotationalEquation2 = new RotationalEquation(bodyA,bodyB,options);
  3910. /**
  3911. * @property {RotationalEquation} rotationalEquation3
  3912. */
  3913. var r3 = this.rotationalEquation3 = new RotationalEquation(bodyA,bodyB,options);
  3914. this.equations.push(r1, r2, r3);
  3915. }
  3916. LockConstraint.prototype = new PointToPointConstraint();
  3917. LockConstraint.constructor = LockConstraint;
  3918. var LockConstraint_update_tmpVec1 = new Vec3();
  3919. var LockConstraint_update_tmpVec2 = new Vec3();
  3920. LockConstraint.prototype.update = function(){
  3921. var bodyA = this.bodyA,
  3922. bodyB = this.bodyB,
  3923. motor = this.motorEquation,
  3924. r1 = this.rotationalEquation1,
  3925. r2 = this.rotationalEquation2,
  3926. r3 = this.rotationalEquation3,
  3927. worldAxisA = LockConstraint_update_tmpVec1,
  3928. worldAxisB = LockConstraint_update_tmpVec2;
  3929. PointToPointConstraint.prototype.update.call(this);
  3930. // These vector pairs must be orthogonal
  3931. bodyA.vectorToWorldFrame(this.xA, r1.axisA);
  3932. bodyB.vectorToWorldFrame(this.yB, r1.axisB);
  3933. bodyA.vectorToWorldFrame(this.yA, r2.axisA);
  3934. bodyB.vectorToWorldFrame(this.zB, r2.axisB);
  3935. bodyA.vectorToWorldFrame(this.zA, r3.axisA);
  3936. bodyB.vectorToWorldFrame(this.xB, r3.axisB);
  3937. };
  3938. },{"../equations/ContactEquation":35,"../equations/RotationalEquation":38,"../equations/RotationalMotorEquation":39,"../math/Vec3":46,"./Constraint":29,"./PointToPointConstraint":33}],33:[function(require,module,exports){
  3939. module.exports = PointToPointConstraint;
  3940. var Constraint = require('./Constraint');
  3941. var ContactEquation = require('../equations/ContactEquation');
  3942. var Vec3 = require('../math/Vec3');
  3943. /**
  3944. * Connects two bodies at given offset points.
  3945. * @class PointToPointConstraint
  3946. * @extends Constraint
  3947. * @constructor
  3948. * @param {Body} bodyA
  3949. * @param {Vec3} pivotA The point relative to the center of mass of bodyA which bodyA is constrained to.
  3950. * @param {Body} bodyB Body that will be constrained in a similar way to the same point as bodyA. We will therefore get a link between bodyA and bodyB. If not specified, bodyA will be constrained to a static point.
  3951. * @param {Vec3} pivotB See pivotA.
  3952. * @param {Number} maxForce The maximum force that should be applied to constrain the bodies.
  3953. *
  3954. * @example
  3955. * var bodyA = new Body({ mass: 1 });
  3956. * var bodyB = new Body({ mass: 1 });
  3957. * bodyA.position.set(-1, 0, 0);
  3958. * bodyB.position.set(1, 0, 0);
  3959. * bodyA.addShape(shapeA);
  3960. * bodyB.addShape(shapeB);
  3961. * world.addBody(bodyA);
  3962. * world.addBody(bodyB);
  3963. * var localPivotA = new Vec3(1, 0, 0);
  3964. * var localPivotB = new Vec3(-1, 0, 0);
  3965. * var constraint = new PointToPointConstraint(bodyA, localPivotA, bodyB, localPivotB);
  3966. * world.addConstraint(constraint);
  3967. */
  3968. function PointToPointConstraint(bodyA,pivotA,bodyB,pivotB,maxForce){
  3969. Constraint.call(this,bodyA,bodyB);
  3970. maxForce = typeof(maxForce) !== 'undefined' ? maxForce : 1e6;
  3971. /**
  3972. * Pivot, defined locally in bodyA.
  3973. * @property {Vec3} pivotA
  3974. */
  3975. this.pivotA = pivotA ? pivotA.clone() : new Vec3();
  3976. /**
  3977. * Pivot, defined locally in bodyB.
  3978. * @property {Vec3} pivotB
  3979. */
  3980. this.pivotB = pivotB ? pivotB.clone() : new Vec3();
  3981. /**
  3982. * @property {ContactEquation} equationX
  3983. */
  3984. var x = this.equationX = new ContactEquation(bodyA,bodyB);
  3985. /**
  3986. * @property {ContactEquation} equationY
  3987. */
  3988. var y = this.equationY = new ContactEquation(bodyA,bodyB);
  3989. /**
  3990. * @property {ContactEquation} equationZ
  3991. */
  3992. var z = this.equationZ = new ContactEquation(bodyA,bodyB);
  3993. // Equations to be fed to the solver
  3994. this.equations.push(x, y, z);
  3995. // Make the equations bidirectional
  3996. x.minForce = y.minForce = z.minForce = -maxForce;
  3997. x.maxForce = y.maxForce = z.maxForce = maxForce;
  3998. x.ni.set(1, 0, 0);
  3999. y.ni.set(0, 1, 0);
  4000. z.ni.set(0, 0, 1);
  4001. }
  4002. PointToPointConstraint.prototype = new Constraint();
  4003. PointToPointConstraint.prototype.update = function(){
  4004. var bodyA = this.bodyA;
  4005. var bodyB = this.bodyB;
  4006. var x = this.equationX;
  4007. var y = this.equationY;
  4008. var z = this.equationZ;
  4009. // Rotate the pivots to world space
  4010. bodyA.quaternion.vmult(this.pivotA,x.ri);
  4011. bodyB.quaternion.vmult(this.pivotB,x.rj);
  4012. y.ri.copy(x.ri);
  4013. y.rj.copy(x.rj);
  4014. z.ri.copy(x.ri);
  4015. z.rj.copy(x.rj);
  4016. };
  4017. },{"../equations/ContactEquation":35,"../math/Vec3":46,"./Constraint":29}],34:[function(require,module,exports){
  4018. module.exports = ConeEquation;
  4019. var Vec3 = require('../math/Vec3');
  4020. var Mat3 = require('../math/Mat3');
  4021. var Equation = require('./Equation');
  4022. /**
  4023. * Cone equation. Works to keep the given body world vectors aligned, or tilted within a given angle from each other.
  4024. * @class ConeEquation
  4025. * @constructor
  4026. * @author schteppe
  4027. * @param {Body} bodyA
  4028. * @param {Body} bodyB
  4029. * @param {Vec3} [options.axisA] Local axis in A
  4030. * @param {Vec3} [options.axisB] Local axis in B
  4031. * @param {Vec3} [options.angle] The "cone angle" to keep
  4032. * @param {number} [options.maxForce=1e6]
  4033. * @extends Equation
  4034. */
  4035. function ConeEquation(bodyA, bodyB, options){
  4036. options = options || {};
  4037. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  4038. Equation.call(this,bodyA,bodyB,-maxForce, maxForce);
  4039. this.axisA = options.axisA ? options.axisA.clone() : new Vec3(1, 0, 0);
  4040. this.axisB = options.axisB ? options.axisB.clone() : new Vec3(0, 1, 0);
  4041. /**
  4042. * The cone angle to keep
  4043. * @property {number} angle
  4044. */
  4045. this.angle = typeof(options.angle) !== 'undefined' ? options.angle : 0;
  4046. }
  4047. ConeEquation.prototype = new Equation();
  4048. ConeEquation.prototype.constructor = ConeEquation;
  4049. var tmpVec1 = new Vec3();
  4050. var tmpVec2 = new Vec3();
  4051. ConeEquation.prototype.computeB = function(h){
  4052. var a = this.a,
  4053. b = this.b,
  4054. ni = this.axisA,
  4055. nj = this.axisB,
  4056. nixnj = tmpVec1,
  4057. njxni = tmpVec2,
  4058. GA = this.jacobianElementA,
  4059. GB = this.jacobianElementB;
  4060. // Caluclate cross products
  4061. ni.cross(nj, nixnj);
  4062. nj.cross(ni, njxni);
  4063. // The angle between two vector is:
  4064. // cos(theta) = a * b / (length(a) * length(b) = { len(a) = len(b) = 1 } = a * b
  4065. // g = a * b
  4066. // gdot = (b x a) * wi + (a x b) * wj
  4067. // G = [0 bxa 0 axb]
  4068. // W = [vi wi vj wj]
  4069. GA.rotational.copy(njxni);
  4070. GB.rotational.copy(nixnj);
  4071. var g = Math.cos(this.angle) - ni.dot(nj),
  4072. GW = this.computeGW(),
  4073. GiMf = this.computeGiMf();
  4074. var B = - g * a - GW * b - h * GiMf;
  4075. return B;
  4076. };
  4077. },{"../math/Mat3":43,"../math/Vec3":46,"./Equation":36}],35:[function(require,module,exports){
  4078. module.exports = ContactEquation;
  4079. var Equation = require('./Equation');
  4080. var Vec3 = require('../math/Vec3');
  4081. var Mat3 = require('../math/Mat3');
  4082. /**
  4083. * Contact/non-penetration constraint equation
  4084. * @class ContactEquation
  4085. * @constructor
  4086. * @author schteppe
  4087. * @param {Body} bodyA
  4088. * @param {Body} bodyB
  4089. * @extends Equation
  4090. */
  4091. function ContactEquation(bodyA, bodyB, maxForce){
  4092. maxForce = typeof(maxForce) !== 'undefined' ? maxForce : 1e6;
  4093. Equation.call(this, bodyA, bodyB, 0, maxForce);
  4094. /**
  4095. * @property restitution
  4096. * @type {Number}
  4097. */
  4098. this.restitution = 0.0; // "bounciness": u1 = -e*u0
  4099. /**
  4100. * World-oriented vector that goes from the center of bi to the contact point.
  4101. * @property {Vec3} ri
  4102. */
  4103. this.ri = new Vec3();
  4104. /**
  4105. * World-oriented vector that starts in body j position and goes to the contact point.
  4106. * @property {Vec3} rj
  4107. */
  4108. this.rj = new Vec3();
  4109. /**
  4110. * Contact normal, pointing out of body i.
  4111. * @property {Vec3} ni
  4112. */
  4113. this.ni = new Vec3();
  4114. }
  4115. ContactEquation.prototype = new Equation();
  4116. ContactEquation.prototype.constructor = ContactEquation;
  4117. var ContactEquation_computeB_temp1 = new Vec3(); // Temp vectors
  4118. var ContactEquation_computeB_temp2 = new Vec3();
  4119. var ContactEquation_computeB_temp3 = new Vec3();
  4120. ContactEquation.prototype.computeB = function(h){
  4121. var a = this.a,
  4122. b = this.b,
  4123. bi = this.bi,
  4124. bj = this.bj,
  4125. ri = this.ri,
  4126. rj = this.rj,
  4127. rixn = ContactEquation_computeB_temp1,
  4128. rjxn = ContactEquation_computeB_temp2,
  4129. vi = bi.velocity,
  4130. wi = bi.angularVelocity,
  4131. fi = bi.force,
  4132. taui = bi.torque,
  4133. vj = bj.velocity,
  4134. wj = bj.angularVelocity,
  4135. fj = bj.force,
  4136. tauj = bj.torque,
  4137. penetrationVec = ContactEquation_computeB_temp3,
  4138. GA = this.jacobianElementA,
  4139. GB = this.jacobianElementB,
  4140. n = this.ni;
  4141. // Caluclate cross products
  4142. ri.cross(n,rixn);
  4143. rj.cross(n,rjxn);
  4144. // g = xj+rj -(xi+ri)
  4145. // G = [ -ni -rixn ni rjxn ]
  4146. n.negate(GA.spatial);
  4147. rixn.negate(GA.rotational);
  4148. GB.spatial.copy(n);
  4149. GB.rotational.copy(rjxn);
  4150. // Calculate the penetration vector
  4151. penetrationVec.copy(bj.position);
  4152. penetrationVec.vadd(rj,penetrationVec);
  4153. penetrationVec.vsub(bi.position,penetrationVec);
  4154. penetrationVec.vsub(ri,penetrationVec);
  4155. var g = n.dot(penetrationVec);
  4156. // Compute iteration
  4157. var ePlusOne = this.restitution + 1;
  4158. var GW = ePlusOne * vj.dot(n) - ePlusOne * vi.dot(n) + wj.dot(rjxn) - wi.dot(rixn);
  4159. var GiMf = this.computeGiMf();
  4160. var B = - g * a - GW * b - h*GiMf;
  4161. return B;
  4162. };
  4163. var ContactEquation_getImpactVelocityAlongNormal_vi = new Vec3();
  4164. var ContactEquation_getImpactVelocityAlongNormal_vj = new Vec3();
  4165. var ContactEquation_getImpactVelocityAlongNormal_xi = new Vec3();
  4166. var ContactEquation_getImpactVelocityAlongNormal_xj = new Vec3();
  4167. var ContactEquation_getImpactVelocityAlongNormal_relVel = new Vec3();
  4168. /**
  4169. * Get the current relative velocity in the contact point.
  4170. * @method getImpactVelocityAlongNormal
  4171. * @return {number}
  4172. */
  4173. ContactEquation.prototype.getImpactVelocityAlongNormal = function(){
  4174. var vi = ContactEquation_getImpactVelocityAlongNormal_vi;
  4175. var vj = ContactEquation_getImpactVelocityAlongNormal_vj;
  4176. var xi = ContactEquation_getImpactVelocityAlongNormal_xi;
  4177. var xj = ContactEquation_getImpactVelocityAlongNormal_xj;
  4178. var relVel = ContactEquation_getImpactVelocityAlongNormal_relVel;
  4179. this.bi.position.vadd(this.ri, xi);
  4180. this.bj.position.vadd(this.rj, xj);
  4181. this.bi.getVelocityAtWorldPoint(xi, vi);
  4182. this.bj.getVelocityAtWorldPoint(xj, vj);
  4183. vi.vsub(vj, relVel);
  4184. return this.ni.dot(relVel);
  4185. };
  4186. },{"../math/Mat3":43,"../math/Vec3":46,"./Equation":36}],36:[function(require,module,exports){
  4187. module.exports = Equation;
  4188. var JacobianElement = require('../math/JacobianElement'),
  4189. Vec3 = require('../math/Vec3');
  4190. /**
  4191. * Equation base class
  4192. * @class Equation
  4193. * @constructor
  4194. * @author schteppe
  4195. * @param {Body} bi
  4196. * @param {Body} bj
  4197. * @param {Number} minForce Minimum (read: negative max) force to be applied by the constraint.
  4198. * @param {Number} maxForce Maximum (read: positive max) force to be applied by the constraint.
  4199. */
  4200. function Equation(bi,bj,minForce,maxForce){
  4201. this.id = Equation.id++;
  4202. /**
  4203. * @property {number} minForce
  4204. */
  4205. this.minForce = typeof(minForce)==="undefined" ? -1e6 : minForce;
  4206. /**
  4207. * @property {number} maxForce
  4208. */
  4209. this.maxForce = typeof(maxForce)==="undefined" ? 1e6 : maxForce;
  4210. /**
  4211. * @property bi
  4212. * @type {Body}
  4213. */
  4214. this.bi = bi;
  4215. /**
  4216. * @property bj
  4217. * @type {Body}
  4218. */
  4219. this.bj = bj;
  4220. /**
  4221. * SPOOK parameter
  4222. * @property {number} a
  4223. */
  4224. this.a = 0.0;
  4225. /**
  4226. * SPOOK parameter
  4227. * @property {number} b
  4228. */
  4229. this.b = 0.0;
  4230. /**
  4231. * SPOOK parameter
  4232. * @property {number} eps
  4233. */
  4234. this.eps = 0.0;
  4235. /**
  4236. * @property {JacobianElement} jacobianElementA
  4237. */
  4238. this.jacobianElementA = new JacobianElement();
  4239. /**
  4240. * @property {JacobianElement} jacobianElementB
  4241. */
  4242. this.jacobianElementB = new JacobianElement();
  4243. /**
  4244. * @property {boolean} enabled
  4245. * @default true
  4246. */
  4247. this.enabled = true;
  4248. /**
  4249. * A number, proportional to the force added to the bodies.
  4250. * @property {number} multiplier
  4251. * @readonly
  4252. */
  4253. this.multiplier = 0;
  4254. // Set typical spook params
  4255. this.setSpookParams(1e7,4,1/60);
  4256. }
  4257. Equation.prototype.constructor = Equation;
  4258. Equation.id = 0;
  4259. /**
  4260. * Recalculates a,b,eps.
  4261. * @method setSpookParams
  4262. */
  4263. Equation.prototype.setSpookParams = function(stiffness,relaxation,timeStep){
  4264. var d = relaxation,
  4265. k = stiffness,
  4266. h = timeStep;
  4267. this.a = 4.0 / (h * (1 + 4 * d));
  4268. this.b = (4.0 * d) / (1 + 4 * d);
  4269. this.eps = 4.0 / (h * h * k * (1 + 4 * d));
  4270. };
  4271. /**
  4272. * Computes the RHS of the SPOOK equation
  4273. * @method computeB
  4274. * @return {Number}
  4275. */
  4276. Equation.prototype.computeB = function(a,b,h){
  4277. var GW = this.computeGW(),
  4278. Gq = this.computeGq(),
  4279. GiMf = this.computeGiMf();
  4280. return - Gq * a - GW * b - GiMf*h;
  4281. };
  4282. /**
  4283. * Computes G*q, where q are the generalized body coordinates
  4284. * @method computeGq
  4285. * @return {Number}
  4286. */
  4287. Equation.prototype.computeGq = function(){
  4288. var GA = this.jacobianElementA,
  4289. GB = this.jacobianElementB,
  4290. bi = this.bi,
  4291. bj = this.bj,
  4292. xi = bi.position,
  4293. xj = bj.position;
  4294. return GA.spatial.dot(xi) + GB.spatial.dot(xj);
  4295. };
  4296. var zero = new Vec3();
  4297. /**
  4298. * Computes G*W, where W are the body velocities
  4299. * @method computeGW
  4300. * @return {Number}
  4301. */
  4302. Equation.prototype.computeGW = function(){
  4303. var GA = this.jacobianElementA,
  4304. GB = this.jacobianElementB,
  4305. bi = this.bi,
  4306. bj = this.bj,
  4307. vi = bi.velocity,
  4308. vj = bj.velocity,
  4309. wi = bi.angularVelocity,
  4310. wj = bj.angularVelocity;
  4311. return GA.multiplyVectors(vi,wi) + GB.multiplyVectors(vj,wj);
  4312. };
  4313. /**
  4314. * Computes G*Wlambda, where W are the body velocities
  4315. * @method computeGWlambda
  4316. * @return {Number}
  4317. */
  4318. Equation.prototype.computeGWlambda = function(){
  4319. var GA = this.jacobianElementA,
  4320. GB = this.jacobianElementB,
  4321. bi = this.bi,
  4322. bj = this.bj,
  4323. vi = bi.vlambda,
  4324. vj = bj.vlambda,
  4325. wi = bi.wlambda,
  4326. wj = bj.wlambda;
  4327. return GA.multiplyVectors(vi,wi) + GB.multiplyVectors(vj,wj);
  4328. };
  4329. /**
  4330. * Computes G*inv(M)*f, where M is the mass matrix with diagonal blocks for each body, and f are the forces on the bodies.
  4331. * @method computeGiMf
  4332. * @return {Number}
  4333. */
  4334. var iMfi = new Vec3(),
  4335. iMfj = new Vec3(),
  4336. invIi_vmult_taui = new Vec3(),
  4337. invIj_vmult_tauj = new Vec3();
  4338. Equation.prototype.computeGiMf = function(){
  4339. var GA = this.jacobianElementA,
  4340. GB = this.jacobianElementB,
  4341. bi = this.bi,
  4342. bj = this.bj,
  4343. fi = bi.force,
  4344. ti = bi.torque,
  4345. fj = bj.force,
  4346. tj = bj.torque,
  4347. invMassi = bi.invMassSolve,
  4348. invMassj = bj.invMassSolve;
  4349. fi.scale(invMassi,iMfi);
  4350. fj.scale(invMassj,iMfj);
  4351. bi.invInertiaWorldSolve.vmult(ti,invIi_vmult_taui);
  4352. bj.invInertiaWorldSolve.vmult(tj,invIj_vmult_tauj);
  4353. return GA.multiplyVectors(iMfi,invIi_vmult_taui) + GB.multiplyVectors(iMfj,invIj_vmult_tauj);
  4354. };
  4355. /**
  4356. * Computes G*inv(M)*G'
  4357. * @method computeGiMGt
  4358. * @return {Number}
  4359. */
  4360. var tmp = new Vec3();
  4361. Equation.prototype.computeGiMGt = function(){
  4362. var GA = this.jacobianElementA,
  4363. GB = this.jacobianElementB,
  4364. bi = this.bi,
  4365. bj = this.bj,
  4366. invMassi = bi.invMassSolve,
  4367. invMassj = bj.invMassSolve,
  4368. invIi = bi.invInertiaWorldSolve,
  4369. invIj = bj.invInertiaWorldSolve,
  4370. result = invMassi + invMassj;
  4371. invIi.vmult(GA.rotational,tmp);
  4372. result += tmp.dot(GA.rotational);
  4373. invIj.vmult(GB.rotational,tmp);
  4374. result += tmp.dot(GB.rotational);
  4375. return result;
  4376. };
  4377. var addToWlambda_temp = new Vec3(),
  4378. addToWlambda_Gi = new Vec3(),
  4379. addToWlambda_Gj = new Vec3(),
  4380. addToWlambda_ri = new Vec3(),
  4381. addToWlambda_rj = new Vec3(),
  4382. addToWlambda_Mdiag = new Vec3();
  4383. /**
  4384. * Add constraint velocity to the bodies.
  4385. * @method addToWlambda
  4386. * @param {Number} deltalambda
  4387. */
  4388. Equation.prototype.addToWlambda = function(deltalambda){
  4389. var GA = this.jacobianElementA,
  4390. GB = this.jacobianElementB,
  4391. bi = this.bi,
  4392. bj = this.bj,
  4393. temp = addToWlambda_temp;
  4394. // Add to linear velocity
  4395. // v_lambda += inv(M) * delta_lamba * G
  4396. bi.vlambda.addScaledVector(bi.invMassSolve * deltalambda, GA.spatial, bi.vlambda);
  4397. bj.vlambda.addScaledVector(bj.invMassSolve * deltalambda, GB.spatial, bj.vlambda);
  4398. // Add to angular velocity
  4399. bi.invInertiaWorldSolve.vmult(GA.rotational,temp);
  4400. bi.wlambda.addScaledVector(deltalambda, temp, bi.wlambda);
  4401. bj.invInertiaWorldSolve.vmult(GB.rotational,temp);
  4402. bj.wlambda.addScaledVector(deltalambda, temp, bj.wlambda);
  4403. };
  4404. /**
  4405. * Compute the denominator part of the SPOOK equation: C = G*inv(M)*G' + eps
  4406. * @method computeInvC
  4407. * @param {Number} eps
  4408. * @return {Number}
  4409. */
  4410. Equation.prototype.computeC = function(){
  4411. return this.computeGiMGt() + this.eps;
  4412. };
  4413. },{"../math/JacobianElement":42,"../math/Vec3":46}],37:[function(require,module,exports){
  4414. module.exports = FrictionEquation;
  4415. var Equation = require('./Equation');
  4416. var Vec3 = require('../math/Vec3');
  4417. var Mat3 = require('../math/Mat3');
  4418. /**
  4419. * Constrains the slipping in a contact along a tangent
  4420. * @class FrictionEquation
  4421. * @constructor
  4422. * @author schteppe
  4423. * @param {Body} bodyA
  4424. * @param {Body} bodyB
  4425. * @param {Number} slipForce should be +-F_friction = +-mu * F_normal = +-mu * m * g
  4426. * @extends Equation
  4427. */
  4428. function FrictionEquation(bodyA, bodyB, slipForce){
  4429. Equation.call(this,bodyA, bodyB, -slipForce, slipForce);
  4430. this.ri = new Vec3();
  4431. this.rj = new Vec3();
  4432. this.t = new Vec3(); // tangent
  4433. }
  4434. FrictionEquation.prototype = new Equation();
  4435. FrictionEquation.prototype.constructor = FrictionEquation;
  4436. var FrictionEquation_computeB_temp1 = new Vec3();
  4437. var FrictionEquation_computeB_temp2 = new Vec3();
  4438. FrictionEquation.prototype.computeB = function(h){
  4439. var a = this.a,
  4440. b = this.b,
  4441. bi = this.bi,
  4442. bj = this.bj,
  4443. ri = this.ri,
  4444. rj = this.rj,
  4445. rixt = FrictionEquation_computeB_temp1,
  4446. rjxt = FrictionEquation_computeB_temp2,
  4447. t = this.t;
  4448. // Caluclate cross products
  4449. ri.cross(t,rixt);
  4450. rj.cross(t,rjxt);
  4451. // G = [-t -rixt t rjxt]
  4452. // And remember, this is a pure velocity constraint, g is always zero!
  4453. var GA = this.jacobianElementA,
  4454. GB = this.jacobianElementB;
  4455. t.negate(GA.spatial);
  4456. rixt.negate(GA.rotational);
  4457. GB.spatial.copy(t);
  4458. GB.rotational.copy(rjxt);
  4459. var GW = this.computeGW();
  4460. var GiMf = this.computeGiMf();
  4461. var B = - GW * b - h * GiMf;
  4462. return B;
  4463. };
  4464. },{"../math/Mat3":43,"../math/Vec3":46,"./Equation":36}],38:[function(require,module,exports){
  4465. module.exports = RotationalEquation;
  4466. var Vec3 = require('../math/Vec3');
  4467. var Mat3 = require('../math/Mat3');
  4468. var Equation = require('./Equation');
  4469. /**
  4470. * Rotational constraint. Works to keep the local vectors orthogonal to each other in world space.
  4471. * @class RotationalEquation
  4472. * @constructor
  4473. * @author schteppe
  4474. * @param {Body} bodyA
  4475. * @param {Body} bodyB
  4476. * @param {Vec3} [options.axisA]
  4477. * @param {Vec3} [options.axisB]
  4478. * @param {number} [options.maxForce]
  4479. * @extends Equation
  4480. */
  4481. function RotationalEquation(bodyA, bodyB, options){
  4482. options = options || {};
  4483. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  4484. Equation.call(this,bodyA,bodyB,-maxForce, maxForce);
  4485. this.axisA = options.axisA ? options.axisA.clone() : new Vec3(1, 0, 0);
  4486. this.axisB = options.axisB ? options.axisB.clone() : new Vec3(0, 1, 0);
  4487. this.maxAngle = Math.PI / 2;
  4488. }
  4489. RotationalEquation.prototype = new Equation();
  4490. RotationalEquation.prototype.constructor = RotationalEquation;
  4491. var tmpVec1 = new Vec3();
  4492. var tmpVec2 = new Vec3();
  4493. RotationalEquation.prototype.computeB = function(h){
  4494. var a = this.a,
  4495. b = this.b,
  4496. ni = this.axisA,
  4497. nj = this.axisB,
  4498. nixnj = tmpVec1,
  4499. njxni = tmpVec2,
  4500. GA = this.jacobianElementA,
  4501. GB = this.jacobianElementB;
  4502. // Caluclate cross products
  4503. ni.cross(nj, nixnj);
  4504. nj.cross(ni, njxni);
  4505. // g = ni * nj
  4506. // gdot = (nj x ni) * wi + (ni x nj) * wj
  4507. // G = [0 njxni 0 nixnj]
  4508. // W = [vi wi vj wj]
  4509. GA.rotational.copy(njxni);
  4510. GB.rotational.copy(nixnj);
  4511. var g = Math.cos(this.maxAngle) - ni.dot(nj),
  4512. GW = this.computeGW(),
  4513. GiMf = this.computeGiMf();
  4514. var B = - g * a - GW * b - h * GiMf;
  4515. return B;
  4516. };
  4517. },{"../math/Mat3":43,"../math/Vec3":46,"./Equation":36}],39:[function(require,module,exports){
  4518. module.exports = RotationalMotorEquation;
  4519. var Vec3 = require('../math/Vec3');
  4520. var Mat3 = require('../math/Mat3');
  4521. var Equation = require('./Equation');
  4522. /**
  4523. * Rotational motor constraint. Tries to keep the relative angular velocity of the bodies to a given value.
  4524. * @class RotationalMotorEquation
  4525. * @constructor
  4526. * @author schteppe
  4527. * @param {Body} bodyA
  4528. * @param {Body} bodyB
  4529. * @param {Number} maxForce
  4530. * @extends Equation
  4531. */
  4532. function RotationalMotorEquation(bodyA, bodyB, maxForce){
  4533. maxForce = typeof(maxForce)!=='undefined' ? maxForce : 1e6;
  4534. Equation.call(this,bodyA,bodyB,-maxForce,maxForce);
  4535. /**
  4536. * World oriented rotational axis
  4537. * @property {Vec3} axisA
  4538. */
  4539. this.axisA = new Vec3();
  4540. /**
  4541. * World oriented rotational axis
  4542. * @property {Vec3} axisB
  4543. */
  4544. this.axisB = new Vec3(); // World oriented rotational axis
  4545. /**
  4546. * Motor velocity
  4547. * @property {Number} targetVelocity
  4548. */
  4549. this.targetVelocity = 0;
  4550. }
  4551. RotationalMotorEquation.prototype = new Equation();
  4552. RotationalMotorEquation.prototype.constructor = RotationalMotorEquation;
  4553. RotationalMotorEquation.prototype.computeB = function(h){
  4554. var a = this.a,
  4555. b = this.b,
  4556. bi = this.bi,
  4557. bj = this.bj,
  4558. axisA = this.axisA,
  4559. axisB = this.axisB,
  4560. GA = this.jacobianElementA,
  4561. GB = this.jacobianElementB;
  4562. // g = 0
  4563. // gdot = axisA * wi - axisB * wj
  4564. // gdot = G * W = G * [vi wi vj wj]
  4565. // =>
  4566. // G = [0 axisA 0 -axisB]
  4567. GA.rotational.copy(axisA);
  4568. axisB.negate(GB.rotational);
  4569. var GW = this.computeGW() - this.targetVelocity,
  4570. GiMf = this.computeGiMf();
  4571. var B = - GW * b - h * GiMf;
  4572. return B;
  4573. };
  4574. },{"../math/Mat3":43,"../math/Vec3":46,"./Equation":36}],40:[function(require,module,exports){
  4575. var Utils = require('../utils/Utils');
  4576. module.exports = ContactMaterial;
  4577. /**
  4578. * Defines what happens when two materials meet.
  4579. * @class ContactMaterial
  4580. * @constructor
  4581. * @param {Material} m1
  4582. * @param {Material} m2
  4583. * @param {object} [options]
  4584. * @param {Number} [options.friction=0.3]
  4585. * @param {Number} [options.restitution=0.3]
  4586. * @param {number} [options.contactEquationStiffness=1e7]
  4587. * @param {number} [options.contactEquationRelaxation=3]
  4588. * @param {number} [options.frictionEquationStiffness=1e7]
  4589. * @param {Number} [options.frictionEquationRelaxation=3]
  4590. */
  4591. function ContactMaterial(m1, m2, options){
  4592. options = Utils.defaults(options, {
  4593. friction: 0.3,
  4594. restitution: 0.3,
  4595. contactEquationStiffness: 1e7,
  4596. contactEquationRelaxation: 3,
  4597. frictionEquationStiffness: 1e7,
  4598. frictionEquationRelaxation: 3
  4599. });
  4600. /**
  4601. * Identifier of this material
  4602. * @property {Number} id
  4603. */
  4604. this.id = ContactMaterial.idCounter++;
  4605. /**
  4606. * Participating materials
  4607. * @property {Array} materials
  4608. * @todo Should be .materialA and .materialB instead
  4609. */
  4610. this.materials = [m1, m2];
  4611. /**
  4612. * Friction coefficient
  4613. * @property {Number} friction
  4614. */
  4615. this.friction = options.friction;
  4616. /**
  4617. * Restitution coefficient
  4618. * @property {Number} restitution
  4619. */
  4620. this.restitution = options.restitution;
  4621. /**
  4622. * Stiffness of the produced contact equations
  4623. * @property {Number} contactEquationStiffness
  4624. */
  4625. this.contactEquationStiffness = options.contactEquationStiffness;
  4626. /**
  4627. * Relaxation time of the produced contact equations
  4628. * @property {Number} contactEquationRelaxation
  4629. */
  4630. this.contactEquationRelaxation = options.contactEquationRelaxation;
  4631. /**
  4632. * Stiffness of the produced friction equations
  4633. * @property {Number} frictionEquationStiffness
  4634. */
  4635. this.frictionEquationStiffness = options.frictionEquationStiffness;
  4636. /**
  4637. * Relaxation time of the produced friction equations
  4638. * @property {Number} frictionEquationRelaxation
  4639. */
  4640. this.frictionEquationRelaxation = options.frictionEquationRelaxation;
  4641. }
  4642. ContactMaterial.idCounter = 0;
  4643. },{"../utils/Utils":69}],41:[function(require,module,exports){
  4644. module.exports = Material;
  4645. /**
  4646. * Defines a physics material.
  4647. * @class Material
  4648. * @constructor
  4649. * @param {object} [options]
  4650. * @author schteppe
  4651. */
  4652. function Material(options){
  4653. var name = '';
  4654. options = options || {};
  4655. // Backwards compatibility fix
  4656. if(typeof(options) === 'string'){
  4657. name = options;
  4658. options = {};
  4659. } else if(typeof(options) === 'object') {
  4660. name = '';
  4661. }
  4662. /**
  4663. * @property name
  4664. * @type {String}
  4665. */
  4666. this.name = name;
  4667. /**
  4668. * material id.
  4669. * @property id
  4670. * @type {number}
  4671. */
  4672. this.id = Material.idCounter++;
  4673. /**
  4674. * Friction for this material. If non-negative, it will be used instead of the friction given by ContactMaterials. If there's no matching ContactMaterial, the value from .defaultContactMaterial in the World will be used.
  4675. * @property {number} friction
  4676. */
  4677. this.friction = typeof(options.friction) !== 'undefined' ? options.friction : -1;
  4678. /**
  4679. * Restitution for this material. If non-negative, it will be used instead of the restitution given by ContactMaterials. If there's no matching ContactMaterial, the value from .defaultContactMaterial in the World will be used.
  4680. * @property {number} restitution
  4681. */
  4682. this.restitution = typeof(options.restitution) !== 'undefined' ? options.restitution : -1;
  4683. }
  4684. Material.idCounter = 0;
  4685. },{}],42:[function(require,module,exports){
  4686. module.exports = JacobianElement;
  4687. var Vec3 = require('./Vec3');
  4688. /**
  4689. * An element containing 6 entries, 3 spatial and 3 rotational degrees of freedom.
  4690. * @class JacobianElement
  4691. * @constructor
  4692. */
  4693. function JacobianElement(){
  4694. /**
  4695. * @property {Vec3} spatial
  4696. */
  4697. this.spatial = new Vec3();
  4698. /**
  4699. * @property {Vec3} rotational
  4700. */
  4701. this.rotational = new Vec3();
  4702. }
  4703. /**
  4704. * Multiply with other JacobianElement
  4705. * @method multiplyElement
  4706. * @param {JacobianElement} element
  4707. * @return {Number}
  4708. */
  4709. JacobianElement.prototype.multiplyElement = function(element){
  4710. return element.spatial.dot(this.spatial) + element.rotational.dot(this.rotational);
  4711. };
  4712. /**
  4713. * Multiply with two vectors
  4714. * @method multiplyVectors
  4715. * @param {Vec3} spatial
  4716. * @param {Vec3} rotational
  4717. * @return {Number}
  4718. */
  4719. JacobianElement.prototype.multiplyVectors = function(spatial,rotational){
  4720. return spatial.dot(this.spatial) + rotational.dot(this.rotational);
  4721. };
  4722. },{"./Vec3":46}],43:[function(require,module,exports){
  4723. module.exports = Mat3;
  4724. var Vec3 = require('./Vec3');
  4725. /**
  4726. * A 3x3 matrix.
  4727. * @class Mat3
  4728. * @constructor
  4729. * @param array elements Array of nine elements. Optional.
  4730. * @author schteppe / http://github.com/schteppe
  4731. */
  4732. function Mat3(elements){
  4733. /**
  4734. * A vector of length 9, containing all matrix elements
  4735. * @property {Array} elements
  4736. */
  4737. if(elements){
  4738. this.elements = elements;
  4739. } else {
  4740. this.elements = [0,0,0,0,0,0,0,0,0];
  4741. }
  4742. }
  4743. /**
  4744. * Sets the matrix to identity
  4745. * @method identity
  4746. * @todo Should perhaps be renamed to setIdentity() to be more clear.
  4747. * @todo Create another function that immediately creates an identity matrix eg. eye()
  4748. */
  4749. Mat3.prototype.identity = function(){
  4750. var e = this.elements;
  4751. e[0] = 1;
  4752. e[1] = 0;
  4753. e[2] = 0;
  4754. e[3] = 0;
  4755. e[4] = 1;
  4756. e[5] = 0;
  4757. e[6] = 0;
  4758. e[7] = 0;
  4759. e[8] = 1;
  4760. };
  4761. /**
  4762. * Set all elements to zero
  4763. * @method setZero
  4764. */
  4765. Mat3.prototype.setZero = function(){
  4766. var e = this.elements;
  4767. e[0] = 0;
  4768. e[1] = 0;
  4769. e[2] = 0;
  4770. e[3] = 0;
  4771. e[4] = 0;
  4772. e[5] = 0;
  4773. e[6] = 0;
  4774. e[7] = 0;
  4775. e[8] = 0;
  4776. };
  4777. /**
  4778. * Sets the matrix diagonal elements from a Vec3
  4779. * @method setTrace
  4780. * @param {Vec3} vec3
  4781. */
  4782. Mat3.prototype.setTrace = function(vec3){
  4783. var e = this.elements;
  4784. e[0] = vec3.x;
  4785. e[4] = vec3.y;
  4786. e[8] = vec3.z;
  4787. };
  4788. /**
  4789. * Gets the matrix diagonal elements
  4790. * @method getTrace
  4791. * @return {Vec3}
  4792. */
  4793. Mat3.prototype.getTrace = function(target){
  4794. var target = target || new Vec3();
  4795. var e = this.elements;
  4796. target.x = e[0];
  4797. target.y = e[4];
  4798. target.z = e[8];
  4799. };
  4800. /**
  4801. * Matrix-Vector multiplication
  4802. * @method vmult
  4803. * @param {Vec3} v The vector to multiply with
  4804. * @param {Vec3} target Optional, target to save the result in.
  4805. */
  4806. Mat3.prototype.vmult = function(v,target){
  4807. target = target || new Vec3();
  4808. var e = this.elements,
  4809. x = v.x,
  4810. y = v.y,
  4811. z = v.z;
  4812. target.x = e[0]*x + e[1]*y + e[2]*z;
  4813. target.y = e[3]*x + e[4]*y + e[5]*z;
  4814. target.z = e[6]*x + e[7]*y + e[8]*z;
  4815. return target;
  4816. };
  4817. /**
  4818. * Matrix-scalar multiplication
  4819. * @method smult
  4820. * @param {Number} s
  4821. */
  4822. Mat3.prototype.smult = function(s){
  4823. for(var i=0; i<this.elements.length; i++){
  4824. this.elements[i] *= s;
  4825. }
  4826. };
  4827. /**
  4828. * Matrix multiplication
  4829. * @method mmult
  4830. * @param {Mat3} m Matrix to multiply with from left side.
  4831. * @return {Mat3} The result.
  4832. */
  4833. Mat3.prototype.mmult = function(m,target){
  4834. var r = target || new Mat3();
  4835. for(var i=0; i<3; i++){
  4836. for(var j=0; j<3; j++){
  4837. var sum = 0.0;
  4838. for(var k=0; k<3; k++){
  4839. sum += m.elements[i+k*3] * this.elements[k+j*3];
  4840. }
  4841. r.elements[i+j*3] = sum;
  4842. }
  4843. }
  4844. return r;
  4845. };
  4846. /**
  4847. * Scale each column of the matrix
  4848. * @method scale
  4849. * @param {Vec3} v
  4850. * @return {Mat3} The result.
  4851. */
  4852. Mat3.prototype.scale = function(v,target){
  4853. target = target || new Mat3();
  4854. var e = this.elements,
  4855. t = target.elements;
  4856. for(var i=0; i!==3; i++){
  4857. t[3*i + 0] = v.x * e[3*i + 0];
  4858. t[3*i + 1] = v.y * e[3*i + 1];
  4859. t[3*i + 2] = v.z * e[3*i + 2];
  4860. }
  4861. return target;
  4862. };
  4863. /**
  4864. * Solve Ax=b
  4865. * @method solve
  4866. * @param {Vec3} b The right hand side
  4867. * @param {Vec3} target Optional. Target vector to save in.
  4868. * @return {Vec3} The solution x
  4869. * @todo should reuse arrays
  4870. */
  4871. Mat3.prototype.solve = function(b,target){
  4872. target = target || new Vec3();
  4873. // Construct equations
  4874. var nr = 3; // num rows
  4875. var nc = 4; // num cols
  4876. var eqns = [];
  4877. for(var i=0; i<nr*nc; i++){
  4878. eqns.push(0);
  4879. }
  4880. var i,j;
  4881. for(i=0; i<3; i++){
  4882. for(j=0; j<3; j++){
  4883. eqns[i+nc*j] = this.elements[i+3*j];
  4884. }
  4885. }
  4886. eqns[3+4*0] = b.x;
  4887. eqns[3+4*1] = b.y;
  4888. eqns[3+4*2] = b.z;
  4889. // Compute right upper triangular version of the matrix - Gauss elimination
  4890. var n = 3, k = n, np;
  4891. var kp = 4; // num rows
  4892. var p, els;
  4893. do {
  4894. i = k - n;
  4895. if (eqns[i+nc*i] === 0) {
  4896. // the pivot is null, swap lines
  4897. for (j = i + 1; j < k; j++) {
  4898. if (eqns[i+nc*j] !== 0) {
  4899. np = kp;
  4900. do { // do ligne( i ) = ligne( i ) + ligne( k )
  4901. p = kp - np;
  4902. eqns[p+nc*i] += eqns[p+nc*j];
  4903. } while (--np);
  4904. break;
  4905. }
  4906. }
  4907. }
  4908. if (eqns[i+nc*i] !== 0) {
  4909. for (j = i + 1; j < k; j++) {
  4910. var multiplier = eqns[i+nc*j] / eqns[i+nc*i];
  4911. np = kp;
  4912. do { // do ligne( k ) = ligne( k ) - multiplier * ligne( i )
  4913. p = kp - np;
  4914. eqns[p+nc*j] = p <= i ? 0 : eqns[p+nc*j] - eqns[p+nc*i] * multiplier ;
  4915. } while (--np);
  4916. }
  4917. }
  4918. } while (--n);
  4919. // Get the solution
  4920. target.z = eqns[2*nc+3] / eqns[2*nc+2];
  4921. target.y = (eqns[1*nc+3] - eqns[1*nc+2]*target.z) / eqns[1*nc+1];
  4922. target.x = (eqns[0*nc+3] - eqns[0*nc+2]*target.z - eqns[0*nc+1]*target.y) / eqns[0*nc+0];
  4923. if(isNaN(target.x) || isNaN(target.y) || isNaN(target.z) || target.x===Infinity || target.y===Infinity || target.z===Infinity){
  4924. throw "Could not solve equation! Got x=["+target.toString()+"], b=["+b.toString()+"], A=["+this.toString()+"]";
  4925. }
  4926. return target;
  4927. };
  4928. /**
  4929. * Get an element in the matrix by index. Index starts at 0, not 1!!!
  4930. * @method e
  4931. * @param {Number} row
  4932. * @param {Number} column
  4933. * @param {Number} value Optional. If provided, the matrix element will be set to this value.
  4934. * @return {Number}
  4935. */
  4936. Mat3.prototype.e = function( row , column ,value){
  4937. if(value===undefined){
  4938. return this.elements[column+3*row];
  4939. } else {
  4940. // Set value
  4941. this.elements[column+3*row] = value;
  4942. }
  4943. };
  4944. /**
  4945. * Copy another matrix into this matrix object.
  4946. * @method copy
  4947. * @param {Mat3} source
  4948. * @return {Mat3} this
  4949. */
  4950. Mat3.prototype.copy = function(source){
  4951. for(var i=0; i < source.elements.length; i++){
  4952. this.elements[i] = source.elements[i];
  4953. }
  4954. return this;
  4955. };
  4956. /**
  4957. * Returns a string representation of the matrix.
  4958. * @method toString
  4959. * @return string
  4960. */
  4961. Mat3.prototype.toString = function(){
  4962. var r = "";
  4963. var sep = ",";
  4964. for(var i=0; i<9; i++){
  4965. r += this.elements[i] + sep;
  4966. }
  4967. return r;
  4968. };
  4969. /**
  4970. * reverse the matrix
  4971. * @method reverse
  4972. * @param {Mat3} target Optional. Target matrix to save in.
  4973. * @return {Mat3} The solution x
  4974. */
  4975. Mat3.prototype.reverse = function(target){
  4976. target = target || new Mat3();
  4977. // Construct equations
  4978. var nr = 3; // num rows
  4979. var nc = 6; // num cols
  4980. var eqns = [];
  4981. for(var i=0; i<nr*nc; i++){
  4982. eqns.push(0);
  4983. }
  4984. var i,j;
  4985. for(i=0; i<3; i++){
  4986. for(j=0; j<3; j++){
  4987. eqns[i+nc*j] = this.elements[i+3*j];
  4988. }
  4989. }
  4990. eqns[3+6*0] = 1;
  4991. eqns[3+6*1] = 0;
  4992. eqns[3+6*2] = 0;
  4993. eqns[4+6*0] = 0;
  4994. eqns[4+6*1] = 1;
  4995. eqns[4+6*2] = 0;
  4996. eqns[5+6*0] = 0;
  4997. eqns[5+6*1] = 0;
  4998. eqns[5+6*2] = 1;
  4999. // Compute right upper triangular version of the matrix - Gauss elimination
  5000. var n = 3, k = n, np;
  5001. var kp = nc; // num rows
  5002. var p;
  5003. do {
  5004. i = k - n;
  5005. if (eqns[i+nc*i] === 0) {
  5006. // the pivot is null, swap lines
  5007. for (j = i + 1; j < k; j++) {
  5008. if (eqns[i+nc*j] !== 0) {
  5009. np = kp;
  5010. do { // do line( i ) = line( i ) + line( k )
  5011. p = kp - np;
  5012. eqns[p+nc*i] += eqns[p+nc*j];
  5013. } while (--np);
  5014. break;
  5015. }
  5016. }
  5017. }
  5018. if (eqns[i+nc*i] !== 0) {
  5019. for (j = i + 1; j < k; j++) {
  5020. var multiplier = eqns[i+nc*j] / eqns[i+nc*i];
  5021. np = kp;
  5022. do { // do line( k ) = line( k ) - multiplier * line( i )
  5023. p = kp - np;
  5024. eqns[p+nc*j] = p <= i ? 0 : eqns[p+nc*j] - eqns[p+nc*i] * multiplier ;
  5025. } while (--np);
  5026. }
  5027. }
  5028. } while (--n);
  5029. // eliminate the upper left triangle of the matrix
  5030. i = 2;
  5031. do {
  5032. j = i-1;
  5033. do {
  5034. var multiplier = eqns[i+nc*j] / eqns[i+nc*i];
  5035. np = nc;
  5036. do {
  5037. p = nc - np;
  5038. eqns[p+nc*j] = eqns[p+nc*j] - eqns[p+nc*i] * multiplier ;
  5039. } while (--np);
  5040. } while (j--);
  5041. } while (--i);
  5042. // operations on the diagonal
  5043. i = 2;
  5044. do {
  5045. var multiplier = 1 / eqns[i+nc*i];
  5046. np = nc;
  5047. do {
  5048. p = nc - np;
  5049. eqns[p+nc*i] = eqns[p+nc*i] * multiplier ;
  5050. } while (--np);
  5051. } while (i--);
  5052. i = 2;
  5053. do {
  5054. j = 2;
  5055. do {
  5056. p = eqns[nr+j+nc*i];
  5057. if( isNaN( p ) || p ===Infinity ){
  5058. throw "Could not reverse! A=["+this.toString()+"]";
  5059. }
  5060. target.e( i , j , p );
  5061. } while (j--);
  5062. } while (i--);
  5063. return target;
  5064. };
  5065. /**
  5066. * Set the matrix from a quaterion
  5067. * @method setRotationFromQuaternion
  5068. * @param {Quaternion} q
  5069. */
  5070. Mat3.prototype.setRotationFromQuaternion = function( q ) {
  5071. var x = q.x, y = q.y, z = q.z, w = q.w,
  5072. x2 = x + x, y2 = y + y, z2 = z + z,
  5073. xx = x * x2, xy = x * y2, xz = x * z2,
  5074. yy = y * y2, yz = y * z2, zz = z * z2,
  5075. wx = w * x2, wy = w * y2, wz = w * z2,
  5076. e = this.elements;
  5077. e[3*0 + 0] = 1 - ( yy + zz );
  5078. e[3*0 + 1] = xy - wz;
  5079. e[3*0 + 2] = xz + wy;
  5080. e[3*1 + 0] = xy + wz;
  5081. e[3*1 + 1] = 1 - ( xx + zz );
  5082. e[3*1 + 2] = yz - wx;
  5083. e[3*2 + 0] = xz - wy;
  5084. e[3*2 + 1] = yz + wx;
  5085. e[3*2 + 2] = 1 - ( xx + yy );
  5086. return this;
  5087. };
  5088. /**
  5089. * Transpose the matrix
  5090. * @method transpose
  5091. * @param {Mat3} target Where to store the result.
  5092. * @return {Mat3} The target Mat3, or a new Mat3 if target was omitted.
  5093. */
  5094. Mat3.prototype.transpose = function( target ) {
  5095. target = target || new Mat3();
  5096. var Mt = target.elements,
  5097. M = this.elements;
  5098. for(var i=0; i!==3; i++){
  5099. for(var j=0; j!==3; j++){
  5100. Mt[3*i + j] = M[3*j + i];
  5101. }
  5102. }
  5103. return target;
  5104. };
  5105. },{"./Vec3":46}],44:[function(require,module,exports){
  5106. module.exports = Quaternion;
  5107. var Vec3 = require('./Vec3');
  5108. /**
  5109. * A Quaternion describes a rotation in 3D space. The Quaternion is mathematically defined as Q = x*i + y*j + z*k + w, where (i,j,k) are imaginary basis vectors. (x,y,z) can be seen as a vector related to the axis of rotation, while the real multiplier, w, is related to the amount of rotation.
  5110. * @class Quaternion
  5111. * @constructor
  5112. * @param {Number} x Multiplier of the imaginary basis vector i.
  5113. * @param {Number} y Multiplier of the imaginary basis vector j.
  5114. * @param {Number} z Multiplier of the imaginary basis vector k.
  5115. * @param {Number} w Multiplier of the real part.
  5116. * @see http://en.wikipedia.org/wiki/Quaternion
  5117. */
  5118. function Quaternion(x,y,z,w){
  5119. /**
  5120. * @property {Number} x
  5121. */
  5122. this.x = x!==undefined ? x : 0;
  5123. /**
  5124. * @property {Number} y
  5125. */
  5126. this.y = y!==undefined ? y : 0;
  5127. /**
  5128. * @property {Number} z
  5129. */
  5130. this.z = z!==undefined ? z : 0;
  5131. /**
  5132. * The multiplier of the real quaternion basis vector.
  5133. * @property {Number} w
  5134. */
  5135. this.w = w!==undefined ? w : 1;
  5136. }
  5137. /**
  5138. * Set the value of the quaternion.
  5139. * @method set
  5140. * @param {Number} x
  5141. * @param {Number} y
  5142. * @param {Number} z
  5143. * @param {Number} w
  5144. */
  5145. Quaternion.prototype.set = function(x,y,z,w){
  5146. this.x = x;
  5147. this.y = y;
  5148. this.z = z;
  5149. this.w = w;
  5150. return this;
  5151. };
  5152. /**
  5153. * Convert to a readable format
  5154. * @method toString
  5155. * @return string
  5156. */
  5157. Quaternion.prototype.toString = function(){
  5158. return this.x+","+this.y+","+this.z+","+this.w;
  5159. };
  5160. /**
  5161. * Convert to an Array
  5162. * @method toArray
  5163. * @return Array
  5164. */
  5165. Quaternion.prototype.toArray = function(){
  5166. return [this.x, this.y, this.z, this.w];
  5167. };
  5168. /**
  5169. * Set the quaternion components given an axis and an angle.
  5170. * @method setFromAxisAngle
  5171. * @param {Vec3} axis
  5172. * @param {Number} angle in radians
  5173. */
  5174. Quaternion.prototype.setFromAxisAngle = function(axis,angle){
  5175. var s = Math.sin(angle*0.5);
  5176. this.x = axis.x * s;
  5177. this.y = axis.y * s;
  5178. this.z = axis.z * s;
  5179. this.w = Math.cos(angle*0.5);
  5180. return this;
  5181. };
  5182. /**
  5183. * Converts the quaternion to axis/angle representation.
  5184. * @method toAxisAngle
  5185. * @param {Vec3} [targetAxis] A vector object to reuse for storing the axis.
  5186. * @return {Array} An array, first elemnt is the axis and the second is the angle in radians.
  5187. */
  5188. Quaternion.prototype.toAxisAngle = function(targetAxis){
  5189. targetAxis = targetAxis || new Vec3();
  5190. this.normalize(); // if w>1 acos and sqrt will produce errors, this cant happen if quaternion is normalised
  5191. var angle = 2 * Math.acos(this.w);
  5192. var s = Math.sqrt(1-this.w*this.w); // assuming quaternion normalised then w is less than 1, so term always positive.
  5193. if (s < 0.001) { // test to avoid divide by zero, s is always positive due to sqrt
  5194. // if s close to zero then direction of axis not important
  5195. targetAxis.x = this.x; // if it is important that axis is normalised then replace with x=1; y=z=0;
  5196. targetAxis.y = this.y;
  5197. targetAxis.z = this.z;
  5198. } else {
  5199. targetAxis.x = this.x / s; // normalise axis
  5200. targetAxis.y = this.y / s;
  5201. targetAxis.z = this.z / s;
  5202. }
  5203. return [targetAxis,angle];
  5204. };
  5205. var sfv_t1 = new Vec3(),
  5206. sfv_t2 = new Vec3();
  5207. /**
  5208. * Set the quaternion value given two vectors. The resulting rotation will be the needed rotation to rotate u to v.
  5209. * @method setFromVectors
  5210. * @param {Vec3} u
  5211. * @param {Vec3} v
  5212. */
  5213. Quaternion.prototype.setFromVectors = function(u,v){
  5214. if(u.isAntiparallelTo(v)){
  5215. var t1 = sfv_t1;
  5216. var t2 = sfv_t2;
  5217. u.tangents(t1,t2);
  5218. this.setFromAxisAngle(t1,Math.PI);
  5219. } else {
  5220. var a = u.cross(v);
  5221. this.x = a.x;
  5222. this.y = a.y;
  5223. this.z = a.z;
  5224. this.w = Math.sqrt(Math.pow(u.norm(),2) * Math.pow(v.norm(),2)) + u.dot(v);
  5225. this.normalize();
  5226. }
  5227. return this;
  5228. };
  5229. /**
  5230. * Quaternion multiplication
  5231. * @method mult
  5232. * @param {Quaternion} q
  5233. * @param {Quaternion} target Optional.
  5234. * @return {Quaternion}
  5235. */
  5236. var Quaternion_mult_va = new Vec3();
  5237. var Quaternion_mult_vb = new Vec3();
  5238. var Quaternion_mult_vaxvb = new Vec3();
  5239. Quaternion.prototype.mult = function(q,target){
  5240. target = target || new Quaternion();
  5241. var ax = this.x, ay = this.y, az = this.z, aw = this.w,
  5242. bx = q.x, by = q.y, bz = q.z, bw = q.w;
  5243. target.x = ax * bw + aw * bx + ay * bz - az * by;
  5244. target.y = ay * bw + aw * by + az * bx - ax * bz;
  5245. target.z = az * bw + aw * bz + ax * by - ay * bx;
  5246. target.w = aw * bw - ax * bx - ay * by - az * bz;
  5247. return target;
  5248. };
  5249. /**
  5250. * Get the inverse quaternion rotation.
  5251. * @method inverse
  5252. * @param {Quaternion} target
  5253. * @return {Quaternion}
  5254. */
  5255. Quaternion.prototype.inverse = function(target){
  5256. var x = this.x, y = this.y, z = this.z, w = this.w;
  5257. target = target || new Quaternion();
  5258. this.conjugate(target);
  5259. var inorm2 = 1/(x*x + y*y + z*z + w*w);
  5260. target.x *= inorm2;
  5261. target.y *= inorm2;
  5262. target.z *= inorm2;
  5263. target.w *= inorm2;
  5264. return target;
  5265. };
  5266. /**
  5267. * Get the quaternion conjugate
  5268. * @method conjugate
  5269. * @param {Quaternion} target
  5270. * @return {Quaternion}
  5271. */
  5272. Quaternion.prototype.conjugate = function(target){
  5273. target = target || new Quaternion();
  5274. target.x = -this.x;
  5275. target.y = -this.y;
  5276. target.z = -this.z;
  5277. target.w = this.w;
  5278. return target;
  5279. };
  5280. /**
  5281. * Normalize the quaternion. Note that this changes the values of the quaternion.
  5282. * @method normalize
  5283. */
  5284. Quaternion.prototype.normalize = function(){
  5285. var l = Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w);
  5286. if ( l === 0 ) {
  5287. this.x = 0;
  5288. this.y = 0;
  5289. this.z = 0;
  5290. this.w = 0;
  5291. } else {
  5292. l = 1 / l;
  5293. this.x *= l;
  5294. this.y *= l;
  5295. this.z *= l;
  5296. this.w *= l;
  5297. }
  5298. return this;
  5299. };
  5300. /**
  5301. * Approximation of quaternion normalization. Works best when quat is already almost-normalized.
  5302. * @method normalizeFast
  5303. * @see http://jsperf.com/fast-quaternion-normalization
  5304. * @author unphased, https://github.com/unphased
  5305. */
  5306. Quaternion.prototype.normalizeFast = function () {
  5307. var f = (3.0-(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w))/2.0;
  5308. if ( f === 0 ) {
  5309. this.x = 0;
  5310. this.y = 0;
  5311. this.z = 0;
  5312. this.w = 0;
  5313. } else {
  5314. this.x *= f;
  5315. this.y *= f;
  5316. this.z *= f;
  5317. this.w *= f;
  5318. }
  5319. return this;
  5320. };
  5321. /**
  5322. * Multiply the quaternion by a vector
  5323. * @method vmult
  5324. * @param {Vec3} v
  5325. * @param {Vec3} target Optional
  5326. * @return {Vec3}
  5327. */
  5328. Quaternion.prototype.vmult = function(v,target){
  5329. target = target || new Vec3();
  5330. var x = v.x,
  5331. y = v.y,
  5332. z = v.z;
  5333. var qx = this.x,
  5334. qy = this.y,
  5335. qz = this.z,
  5336. qw = this.w;
  5337. // q*v
  5338. var ix = qw * x + qy * z - qz * y,
  5339. iy = qw * y + qz * x - qx * z,
  5340. iz = qw * z + qx * y - qy * x,
  5341. iw = -qx * x - qy * y - qz * z;
  5342. target.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
  5343. target.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
  5344. target.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
  5345. return target;
  5346. };
  5347. /**
  5348. * Copies value of source to this quaternion.
  5349. * @method copy
  5350. * @param {Quaternion} source
  5351. * @return {Quaternion} this
  5352. */
  5353. Quaternion.prototype.copy = function(source){
  5354. this.x = source.x;
  5355. this.y = source.y;
  5356. this.z = source.z;
  5357. this.w = source.w;
  5358. return this;
  5359. };
  5360. /**
  5361. * Convert the quaternion to euler angle representation. Order: YZX, as this page describes: http://www.euclideanspace.com/maths/standards/index.htm
  5362. * @method toEuler
  5363. * @param {Vec3} target
  5364. * @param string order Three-character string e.g. "YZX", which also is default.
  5365. */
  5366. Quaternion.prototype.toEuler = function(target,order){
  5367. order = order || "YZX";
  5368. var heading, attitude, bank;
  5369. var x = this.x, y = this.y, z = this.z, w = this.w;
  5370. switch(order){
  5371. case "YZX":
  5372. var test = x*y + z*w;
  5373. if (test > 0.499) { // singularity at north pole
  5374. heading = 2 * Math.atan2(x,w);
  5375. attitude = Math.PI/2;
  5376. bank = 0;
  5377. }
  5378. if (test < -0.499) { // singularity at south pole
  5379. heading = -2 * Math.atan2(x,w);
  5380. attitude = - Math.PI/2;
  5381. bank = 0;
  5382. }
  5383. if(isNaN(heading)){
  5384. var sqx = x*x;
  5385. var sqy = y*y;
  5386. var sqz = z*z;
  5387. heading = Math.atan2(2*y*w - 2*x*z , 1 - 2*sqy - 2*sqz); // Heading
  5388. attitude = Math.asin(2*test); // attitude
  5389. bank = Math.atan2(2*x*w - 2*y*z , 1 - 2*sqx - 2*sqz); // bank
  5390. }
  5391. break;
  5392. default:
  5393. throw new Error("Euler order "+order+" not supported yet.");
  5394. }
  5395. target.y = heading;
  5396. target.z = attitude;
  5397. target.x = bank;
  5398. };
  5399. /**
  5400. * See http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m
  5401. * @method setFromEuler
  5402. * @param {Number} x
  5403. * @param {Number} y
  5404. * @param {Number} z
  5405. * @param {String} order The order to apply angles: 'XYZ' or 'YXZ' or any other combination
  5406. */
  5407. Quaternion.prototype.setFromEuler = function ( x, y, z, order ) {
  5408. order = order || "XYZ";
  5409. var c1 = Math.cos( x / 2 );
  5410. var c2 = Math.cos( y / 2 );
  5411. var c3 = Math.cos( z / 2 );
  5412. var s1 = Math.sin( x / 2 );
  5413. var s2 = Math.sin( y / 2 );
  5414. var s3 = Math.sin( z / 2 );
  5415. if ( order === 'XYZ' ) {
  5416. this.x = s1 * c2 * c3 + c1 * s2 * s3;
  5417. this.y = c1 * s2 * c3 - s1 * c2 * s3;
  5418. this.z = c1 * c2 * s3 + s1 * s2 * c3;
  5419. this.w = c1 * c2 * c3 - s1 * s2 * s3;
  5420. } else if ( order === 'YXZ' ) {
  5421. this.x = s1 * c2 * c3 + c1 * s2 * s3;
  5422. this.y = c1 * s2 * c3 - s1 * c2 * s3;
  5423. this.z = c1 * c2 * s3 - s1 * s2 * c3;
  5424. this.w = c1 * c2 * c3 + s1 * s2 * s3;
  5425. } else if ( order === 'ZXY' ) {
  5426. this.x = s1 * c2 * c3 - c1 * s2 * s3;
  5427. this.y = c1 * s2 * c3 + s1 * c2 * s3;
  5428. this.z = c1 * c2 * s3 + s1 * s2 * c3;
  5429. this.w = c1 * c2 * c3 - s1 * s2 * s3;
  5430. } else if ( order === 'ZYX' ) {
  5431. this.x = s1 * c2 * c3 - c1 * s2 * s3;
  5432. this.y = c1 * s2 * c3 + s1 * c2 * s3;
  5433. this.z = c1 * c2 * s3 - s1 * s2 * c3;
  5434. this.w = c1 * c2 * c3 + s1 * s2 * s3;
  5435. } else if ( order === 'YZX' ) {
  5436. this.x = s1 * c2 * c3 + c1 * s2 * s3;
  5437. this.y = c1 * s2 * c3 + s1 * c2 * s3;
  5438. this.z = c1 * c2 * s3 - s1 * s2 * c3;
  5439. this.w = c1 * c2 * c3 - s1 * s2 * s3;
  5440. } else if ( order === 'XZY' ) {
  5441. this.x = s1 * c2 * c3 - c1 * s2 * s3;
  5442. this.y = c1 * s2 * c3 - s1 * c2 * s3;
  5443. this.z = c1 * c2 * s3 + s1 * s2 * c3;
  5444. this.w = c1 * c2 * c3 + s1 * s2 * s3;
  5445. }
  5446. return this;
  5447. };
  5448. /**
  5449. * @method clone
  5450. * @return {Quaternion}
  5451. */
  5452. Quaternion.prototype.clone = function(){
  5453. return new Quaternion(this.x, this.y, this.z, this.w);
  5454. };
  5455. /**
  5456. * Performs a spherical linear interpolation between two quat
  5457. *
  5458. * @method slerp
  5459. * @param {Quaternion} toQuat second operand
  5460. * @param {Number} t interpolation amount between the self quaternion and toQuat
  5461. * @param {Quaternion} [target] A quaternion to store the result in. If not provided, a new one will be created.
  5462. * @returns {Quaternion} The "target" object
  5463. */
  5464. Quaternion.prototype.slerp = function (toQuat, t, target) {
  5465. target = target || new Quaternion();
  5466. var ax = this.x,
  5467. ay = this.y,
  5468. az = this.z,
  5469. aw = this.w,
  5470. bx = toQuat.x,
  5471. by = toQuat.y,
  5472. bz = toQuat.z,
  5473. bw = toQuat.w;
  5474. var omega, cosom, sinom, scale0, scale1;
  5475. // calc cosine
  5476. cosom = ax * bx + ay * by + az * bz + aw * bw;
  5477. // adjust signs (if necessary)
  5478. if ( cosom < 0.0 ) {
  5479. cosom = -cosom;
  5480. bx = - bx;
  5481. by = - by;
  5482. bz = - bz;
  5483. bw = - bw;
  5484. }
  5485. // calculate coefficients
  5486. if ( (1.0 - cosom) > 0.000001 ) {
  5487. // standard case (slerp)
  5488. omega = Math.acos(cosom);
  5489. sinom = Math.sin(omega);
  5490. scale0 = Math.sin((1.0 - t) * omega) / sinom;
  5491. scale1 = Math.sin(t * omega) / sinom;
  5492. } else {
  5493. // "from" and "to" quaternions are very close
  5494. // ... so we can do a linear interpolation
  5495. scale0 = 1.0 - t;
  5496. scale1 = t;
  5497. }
  5498. // calculate final values
  5499. target.x = scale0 * ax + scale1 * bx;
  5500. target.y = scale0 * ay + scale1 * by;
  5501. target.z = scale0 * az + scale1 * bz;
  5502. target.w = scale0 * aw + scale1 * bw;
  5503. return target;
  5504. };
  5505. /**
  5506. * Rotate an absolute orientation quaternion given an angular velocity and a time step.
  5507. * @param {Vec3} angularVelocity
  5508. * @param {number} dt
  5509. * @param {Vec3} angularFactor
  5510. * @param {Quaternion} target
  5511. * @return {Quaternion} The "target" object
  5512. */
  5513. Quaternion.prototype.integrate = function(angularVelocity, dt, angularFactor, target){
  5514. target = target || new Quaternion();
  5515. var ax = angularVelocity.x * angularFactor.x,
  5516. ay = angularVelocity.y * angularFactor.y,
  5517. az = angularVelocity.z * angularFactor.z,
  5518. bx = this.x,
  5519. by = this.y,
  5520. bz = this.z,
  5521. bw = this.w;
  5522. var half_dt = dt * 0.5;
  5523. target.x += half_dt * (ax * bw + ay * bz - az * by);
  5524. target.y += half_dt * (ay * bw + az * bx - ax * bz);
  5525. target.z += half_dt * (az * bw + ax * by - ay * bx);
  5526. target.w += half_dt * (- ax * bx - ay * by - az * bz);
  5527. return target;
  5528. };
  5529. },{"./Vec3":46}],45:[function(require,module,exports){
  5530. var Vec3 = require('./Vec3');
  5531. var Quaternion = require('./Quaternion');
  5532. module.exports = Transform;
  5533. /**
  5534. * @class Transform
  5535. * @constructor
  5536. */
  5537. function Transform(options) {
  5538. options = options || {};
  5539. /**
  5540. * @property {Vec3} position
  5541. */
  5542. this.position = new Vec3();
  5543. if(options.position){
  5544. this.position.copy(options.position);
  5545. }
  5546. /**
  5547. * @property {Quaternion} quaternion
  5548. */
  5549. this.quaternion = new Quaternion();
  5550. if(options.quaternion){
  5551. this.quaternion.copy(options.quaternion);
  5552. }
  5553. }
  5554. var tmpQuat = new Quaternion();
  5555. /**
  5556. * @static
  5557. * @method pointToLocaFrame
  5558. * @param {Vec3} position
  5559. * @param {Quaternion} quaternion
  5560. * @param {Vec3} worldPoint
  5561. * @param {Vec3} result
  5562. */
  5563. Transform.pointToLocalFrame = function(position, quaternion, worldPoint, result){
  5564. var result = result || new Vec3();
  5565. worldPoint.vsub(position, result);
  5566. quaternion.conjugate(tmpQuat);
  5567. tmpQuat.vmult(result, result);
  5568. return result;
  5569. };
  5570. /**
  5571. * Get a global point in local transform coordinates.
  5572. * @method pointToLocal
  5573. * @param {Vec3} point
  5574. * @param {Vec3} result
  5575. * @return {Vec3} The "result" vector object
  5576. */
  5577. Transform.prototype.pointToLocal = function(worldPoint, result){
  5578. return Transform.pointToLocalFrame(this.position, this.quaternion, worldPoint, result);
  5579. };
  5580. /**
  5581. * @static
  5582. * @method pointToWorldFrame
  5583. * @param {Vec3} position
  5584. * @param {Vec3} quaternion
  5585. * @param {Vec3} localPoint
  5586. * @param {Vec3} result
  5587. */
  5588. Transform.pointToWorldFrame = function(position, quaternion, localPoint, result){
  5589. var result = result || new Vec3();
  5590. quaternion.vmult(localPoint, result);
  5591. result.vadd(position, result);
  5592. return result;
  5593. };
  5594. /**
  5595. * Get a local point in global transform coordinates.
  5596. * @method pointToWorld
  5597. * @param {Vec3} point
  5598. * @param {Vec3} result
  5599. * @return {Vec3} The "result" vector object
  5600. */
  5601. Transform.prototype.pointToWorld = function(localPoint, result){
  5602. return Transform.pointToWorldFrame(this.position, this.quaternion, localPoint, result);
  5603. };
  5604. Transform.prototype.vectorToWorldFrame = function(localVector, result){
  5605. var result = result || new Vec3();
  5606. this.quaternion.vmult(localVector, result);
  5607. return result;
  5608. };
  5609. Transform.vectorToWorldFrame = function(quaternion, localVector, result){
  5610. quaternion.vmult(localVector, result);
  5611. return result;
  5612. };
  5613. Transform.vectorToLocalFrame = function(position, quaternion, worldVector, result){
  5614. var result = result || new Vec3();
  5615. quaternion.w *= -1;
  5616. quaternion.vmult(worldVector, result);
  5617. quaternion.w *= -1;
  5618. return result;
  5619. };
  5620. },{"./Quaternion":44,"./Vec3":46}],46:[function(require,module,exports){
  5621. module.exports = Vec3;
  5622. var Mat3 = require('./Mat3');
  5623. /**
  5624. * 3-dimensional vector
  5625. * @class Vec3
  5626. * @constructor
  5627. * @param {Number} x
  5628. * @param {Number} y
  5629. * @param {Number} z
  5630. * @author schteppe
  5631. * @example
  5632. * var v = new Vec3(1, 2, 3);
  5633. * console.log('x=' + v.x); // x=1
  5634. */
  5635. function Vec3(x,y,z){
  5636. /**
  5637. * @property x
  5638. * @type {Number}
  5639. */
  5640. this.x = x||0.0;
  5641. /**
  5642. * @property y
  5643. * @type {Number}
  5644. */
  5645. this.y = y||0.0;
  5646. /**
  5647. * @property z
  5648. * @type {Number}
  5649. */
  5650. this.z = z||0.0;
  5651. }
  5652. /**
  5653. * @static
  5654. * @property {Vec3} ZERO
  5655. */
  5656. Vec3.ZERO = new Vec3(0, 0, 0);
  5657. /**
  5658. * @static
  5659. * @property {Vec3} UNIT_X
  5660. */
  5661. Vec3.UNIT_X = new Vec3(1, 0, 0);
  5662. /**
  5663. * @static
  5664. * @property {Vec3} UNIT_Y
  5665. */
  5666. Vec3.UNIT_Y = new Vec3(0, 1, 0);
  5667. /**
  5668. * @static
  5669. * @property {Vec3} UNIT_Z
  5670. */
  5671. Vec3.UNIT_Z = new Vec3(0, 0, 1);
  5672. /**
  5673. * Vector cross product
  5674. * @method cross
  5675. * @param {Vec3} v
  5676. * @param {Vec3} target Optional. Target to save in.
  5677. * @return {Vec3}
  5678. */
  5679. Vec3.prototype.cross = function(v,target){
  5680. var vx=v.x, vy=v.y, vz=v.z, x=this.x, y=this.y, z=this.z;
  5681. target = target || new Vec3();
  5682. target.x = (y * vz) - (z * vy);
  5683. target.y = (z * vx) - (x * vz);
  5684. target.z = (x * vy) - (y * vx);
  5685. return target;
  5686. };
  5687. /**
  5688. * Set the vectors' 3 elements
  5689. * @method set
  5690. * @param {Number} x
  5691. * @param {Number} y
  5692. * @param {Number} z
  5693. * @return Vec3
  5694. */
  5695. Vec3.prototype.set = function(x,y,z){
  5696. this.x = x;
  5697. this.y = y;
  5698. this.z = z;
  5699. return this;
  5700. };
  5701. /**
  5702. * Set all components of the vector to zero.
  5703. * @method setZero
  5704. */
  5705. Vec3.prototype.setZero = function(){
  5706. this.x = this.y = this.z = 0;
  5707. };
  5708. /**
  5709. * Vector addition
  5710. * @method vadd
  5711. * @param {Vec3} v
  5712. * @param {Vec3} target Optional.
  5713. * @return {Vec3}
  5714. */
  5715. Vec3.prototype.vadd = function(v,target){
  5716. if(target){
  5717. target.x = v.x + this.x;
  5718. target.y = v.y + this.y;
  5719. target.z = v.z + this.z;
  5720. } else {
  5721. return new Vec3(this.x + v.x,
  5722. this.y + v.y,
  5723. this.z + v.z);
  5724. }
  5725. };
  5726. /**
  5727. * Vector subtraction
  5728. * @method vsub
  5729. * @param {Vec3} v
  5730. * @param {Vec3} target Optional. Target to save in.
  5731. * @return {Vec3}
  5732. */
  5733. Vec3.prototype.vsub = function(v,target){
  5734. if(target){
  5735. target.x = this.x - v.x;
  5736. target.y = this.y - v.y;
  5737. target.z = this.z - v.z;
  5738. } else {
  5739. return new Vec3(this.x-v.x,
  5740. this.y-v.y,
  5741. this.z-v.z);
  5742. }
  5743. };
  5744. /**
  5745. * Get the cross product matrix a_cross from a vector, such that a x b = a_cross * b = c
  5746. * @method crossmat
  5747. * @see http://www8.cs.umu.se/kurser/TDBD24/VT06/lectures/Lecture6.pdf
  5748. * @return {Mat3}
  5749. */
  5750. Vec3.prototype.crossmat = function(){
  5751. return new Mat3([ 0, -this.z, this.y,
  5752. this.z, 0, -this.x,
  5753. -this.y, this.x, 0]);
  5754. };
  5755. /**
  5756. * Normalize the vector. Note that this changes the values in the vector.
  5757. * @method normalize
  5758. * @return {Number} Returns the norm of the vector
  5759. */
  5760. Vec3.prototype.normalize = function(){
  5761. var x=this.x, y=this.y, z=this.z;
  5762. var n = Math.sqrt(x*x + y*y + z*z);
  5763. if(n>0.0){
  5764. var invN = 1/n;
  5765. this.x *= invN;
  5766. this.y *= invN;
  5767. this.z *= invN;
  5768. } else {
  5769. // Make something up
  5770. this.x = 0;
  5771. this.y = 0;
  5772. this.z = 0;
  5773. }
  5774. return n;
  5775. };
  5776. /**
  5777. * Get the version of this vector that is of length 1.
  5778. * @method unit
  5779. * @param {Vec3} target Optional target to save in
  5780. * @return {Vec3} Returns the unit vector
  5781. */
  5782. Vec3.prototype.unit = function(target){
  5783. target = target || new Vec3();
  5784. var x=this.x, y=this.y, z=this.z;
  5785. var ninv = Math.sqrt(x*x + y*y + z*z);
  5786. if(ninv>0.0){
  5787. ninv = 1.0/ninv;
  5788. target.x = x * ninv;
  5789. target.y = y * ninv;
  5790. target.z = z * ninv;
  5791. } else {
  5792. target.x = 1;
  5793. target.y = 0;
  5794. target.z = 0;
  5795. }
  5796. return target;
  5797. };
  5798. /**
  5799. * Get the length of the vector
  5800. * @method norm
  5801. * @return {Number}
  5802. * @deprecated Use .length() instead
  5803. */
  5804. Vec3.prototype.norm = function(){
  5805. var x=this.x, y=this.y, z=this.z;
  5806. return Math.sqrt(x*x + y*y + z*z);
  5807. };
  5808. /**
  5809. * Get the length of the vector
  5810. * @method length
  5811. * @return {Number}
  5812. */
  5813. Vec3.prototype.length = Vec3.prototype.norm;
  5814. /**
  5815. * Get the squared length of the vector
  5816. * @method norm2
  5817. * @return {Number}
  5818. * @deprecated Use .lengthSquared() instead.
  5819. */
  5820. Vec3.prototype.norm2 = function(){
  5821. return this.dot(this);
  5822. };
  5823. /**
  5824. * Get the squared length of the vector.
  5825. * @method lengthSquared
  5826. * @return {Number}
  5827. */
  5828. Vec3.prototype.lengthSquared = Vec3.prototype.norm2;
  5829. /**
  5830. * Get distance from this point to another point
  5831. * @method distanceTo
  5832. * @param {Vec3} p
  5833. * @return {Number}
  5834. */
  5835. Vec3.prototype.distanceTo = function(p){
  5836. var x=this.x, y=this.y, z=this.z;
  5837. var px=p.x, py=p.y, pz=p.z;
  5838. return Math.sqrt((px-x)*(px-x)+
  5839. (py-y)*(py-y)+
  5840. (pz-z)*(pz-z));
  5841. };
  5842. /**
  5843. * Get squared distance from this point to another point
  5844. * @method distanceSquared
  5845. * @param {Vec3} p
  5846. * @return {Number}
  5847. */
  5848. Vec3.prototype.distanceSquared = function(p){
  5849. var x=this.x, y=this.y, z=this.z;
  5850. var px=p.x, py=p.y, pz=p.z;
  5851. return (px-x)*(px-x) + (py-y)*(py-y) + (pz-z)*(pz-z);
  5852. };
  5853. /**
  5854. * Multiply all the components of the vector with a scalar.
  5855. * @deprecated Use .scale instead
  5856. * @method mult
  5857. * @param {Number} scalar
  5858. * @param {Vec3} target The vector to save the result in.
  5859. * @return {Vec3}
  5860. * @deprecated Use .scale() instead
  5861. */
  5862. Vec3.prototype.mult = function(scalar,target){
  5863. target = target || new Vec3();
  5864. var x = this.x,
  5865. y = this.y,
  5866. z = this.z;
  5867. target.x = scalar * x;
  5868. target.y = scalar * y;
  5869. target.z = scalar * z;
  5870. return target;
  5871. };
  5872. /**
  5873. * Multiply the vector with an other vector, component-wise.
  5874. * @method mult
  5875. * @param {Number} vector
  5876. * @param {Vec3} target The vector to save the result in.
  5877. * @return {Vec3}
  5878. */
  5879. Vec3.prototype.vmul = function(vector, target){
  5880. target = target || new Vec3();
  5881. target.x = vector.x * this.x;
  5882. target.y = vector.y * this.y;
  5883. target.z = vector.z * this.z;
  5884. return target;
  5885. };
  5886. /**
  5887. * Multiply the vector with a scalar.
  5888. * @method scale
  5889. * @param {Number} scalar
  5890. * @param {Vec3} target
  5891. * @return {Vec3}
  5892. */
  5893. Vec3.prototype.scale = Vec3.prototype.mult;
  5894. /**
  5895. * Scale a vector and add it to this vector. Save the result in "target". (target = this + vector * scalar)
  5896. * @method addScaledVector
  5897. * @param {Number} scalar
  5898. * @param {Vec3} vector
  5899. * @param {Vec3} target The vector to save the result in.
  5900. * @return {Vec3}
  5901. */
  5902. Vec3.prototype.addScaledVector = function(scalar, vector, target){
  5903. target = target || new Vec3();
  5904. target.x = this.x + scalar * vector.x;
  5905. target.y = this.y + scalar * vector.y;
  5906. target.z = this.z + scalar * vector.z;
  5907. return target;
  5908. };
  5909. /**
  5910. * Calculate dot product
  5911. * @method dot
  5912. * @param {Vec3} v
  5913. * @return {Number}
  5914. */
  5915. Vec3.prototype.dot = function(v){
  5916. return this.x * v.x + this.y * v.y + this.z * v.z;
  5917. };
  5918. /**
  5919. * @method isZero
  5920. * @return bool
  5921. */
  5922. Vec3.prototype.isZero = function(){
  5923. return this.x===0 && this.y===0 && this.z===0;
  5924. };
  5925. /**
  5926. * Make the vector point in the opposite direction.
  5927. * @method negate
  5928. * @param {Vec3} target Optional target to save in
  5929. * @return {Vec3}
  5930. */
  5931. Vec3.prototype.negate = function(target){
  5932. target = target || new Vec3();
  5933. target.x = -this.x;
  5934. target.y = -this.y;
  5935. target.z = -this.z;
  5936. return target;
  5937. };
  5938. /**
  5939. * Compute two artificial tangents to the vector
  5940. * @method tangents
  5941. * @param {Vec3} t1 Vector object to save the first tangent in
  5942. * @param {Vec3} t2 Vector object to save the second tangent in
  5943. */
  5944. var Vec3_tangents_n = new Vec3();
  5945. var Vec3_tangents_randVec = new Vec3();
  5946. Vec3.prototype.tangents = function(t1,t2){
  5947. var norm = this.norm();
  5948. if(norm>0.0){
  5949. var n = Vec3_tangents_n;
  5950. var inorm = 1/norm;
  5951. n.set(this.x*inorm,this.y*inorm,this.z*inorm);
  5952. var randVec = Vec3_tangents_randVec;
  5953. if(Math.abs(n.x) < 0.9){
  5954. randVec.set(1,0,0);
  5955. n.cross(randVec,t1);
  5956. } else {
  5957. randVec.set(0,1,0);
  5958. n.cross(randVec,t1);
  5959. }
  5960. n.cross(t1,t2);
  5961. } else {
  5962. // The normal length is zero, make something up
  5963. t1.set(1, 0, 0);
  5964. t2.set(0, 1, 0);
  5965. }
  5966. };
  5967. /**
  5968. * Converts to a more readable format
  5969. * @method toString
  5970. * @return string
  5971. */
  5972. Vec3.prototype.toString = function(){
  5973. return this.x+","+this.y+","+this.z;
  5974. };
  5975. /**
  5976. * Converts to an array
  5977. * @method toArray
  5978. * @return Array
  5979. */
  5980. Vec3.prototype.toArray = function(){
  5981. return [this.x, this.y, this.z];
  5982. };
  5983. /**
  5984. * Copies value of source to this vector.
  5985. * @method copy
  5986. * @param {Vec3} source
  5987. * @return {Vec3} this
  5988. */
  5989. Vec3.prototype.copy = function(source){
  5990. this.x = source.x;
  5991. this.y = source.y;
  5992. this.z = source.z;
  5993. return this;
  5994. };
  5995. /**
  5996. * Do a linear interpolation between two vectors
  5997. * @method lerp
  5998. * @param {Vec3} v
  5999. * @param {Number} t A number between 0 and 1. 0 will make this function return u, and 1 will make it return v. Numbers in between will generate a vector in between them.
  6000. * @param {Vec3} target
  6001. */
  6002. Vec3.prototype.lerp = function(v,t,target){
  6003. var x=this.x, y=this.y, z=this.z;
  6004. target.x = x + (v.x-x)*t;
  6005. target.y = y + (v.y-y)*t;
  6006. target.z = z + (v.z-z)*t;
  6007. };
  6008. /**
  6009. * Check if a vector equals is almost equal to another one.
  6010. * @method almostEquals
  6011. * @param {Vec3} v
  6012. * @param {Number} precision
  6013. * @return bool
  6014. */
  6015. Vec3.prototype.almostEquals = function(v,precision){
  6016. if(precision===undefined){
  6017. precision = 1e-6;
  6018. }
  6019. if( Math.abs(this.x-v.x)>precision ||
  6020. Math.abs(this.y-v.y)>precision ||
  6021. Math.abs(this.z-v.z)>precision){
  6022. return false;
  6023. }
  6024. return true;
  6025. };
  6026. /**
  6027. * Check if a vector is almost zero
  6028. * @method almostZero
  6029. * @param {Number} precision
  6030. */
  6031. Vec3.prototype.almostZero = function(precision){
  6032. if(precision===undefined){
  6033. precision = 1e-6;
  6034. }
  6035. if( Math.abs(this.x)>precision ||
  6036. Math.abs(this.y)>precision ||
  6037. Math.abs(this.z)>precision){
  6038. return false;
  6039. }
  6040. return true;
  6041. };
  6042. var antip_neg = new Vec3();
  6043. /**
  6044. * Check if the vector is anti-parallel to another vector.
  6045. * @method isAntiparallelTo
  6046. * @param {Vec3} v
  6047. * @param {Number} precision Set to zero for exact comparisons
  6048. * @return {Boolean}
  6049. */
  6050. Vec3.prototype.isAntiparallelTo = function(v,precision){
  6051. this.negate(antip_neg);
  6052. return antip_neg.almostEquals(v,precision);
  6053. };
  6054. /**
  6055. * Clone the vector
  6056. * @method clone
  6057. * @return {Vec3}
  6058. */
  6059. Vec3.prototype.clone = function(){
  6060. return new Vec3(this.x, this.y, this.z);
  6061. };
  6062. },{"./Mat3":43}],47:[function(require,module,exports){
  6063. module.exports = Body;
  6064. var EventTarget = require('../utils/EventTarget');
  6065. var Shape = require('../shapes/Shape');
  6066. var Vec3 = require('../math/Vec3');
  6067. var Mat3 = require('../math/Mat3');
  6068. var Quaternion = require('../math/Quaternion');
  6069. var Material = require('../material/Material');
  6070. var AABB = require('../collision/AABB');
  6071. var Box = require('../shapes/Box');
  6072. /**
  6073. * Base class for all body types.
  6074. * @class Body
  6075. * @constructor
  6076. * @extends EventTarget
  6077. * @param {object} [options]
  6078. * @param {Vec3} [options.position]
  6079. * @param {Vec3} [options.velocity]
  6080. * @param {Vec3} [options.angularVelocity]
  6081. * @param {Quaternion} [options.quaternion]
  6082. * @param {number} [options.mass]
  6083. * @param {Material} [options.material]
  6084. * @param {number} [options.type]
  6085. * @param {number} [options.linearDamping=0.01]
  6086. * @param {number} [options.angularDamping=0.01]
  6087. * @param {boolean} [options.allowSleep=true]
  6088. * @param {number} [options.sleepSpeedLimit=0.1]
  6089. * @param {number} [options.sleepTimeLimit=1]
  6090. * @param {number} [options.collisionFilterGroup=1]
  6091. * @param {number} [options.collisionFilterMask=1]
  6092. * @param {boolean} [options.fixedRotation=false]
  6093. * @param {Vec3} [options.linearFactor]
  6094. * @param {Vec3} [options.angularFactor]
  6095. * @param {Shape} [options.shape]
  6096. * @example
  6097. * var body = new Body({
  6098. * mass: 1
  6099. * });
  6100. * var shape = new Sphere(1);
  6101. * body.addShape(shape);
  6102. * world.addBody(body);
  6103. */
  6104. function Body(options){
  6105. options = options || {};
  6106. EventTarget.apply(this);
  6107. this.id = Body.idCounter++;
  6108. /**
  6109. * Reference to the world the body is living in
  6110. * @property world
  6111. * @type {World}
  6112. */
  6113. this.world = null;
  6114. /**
  6115. * Callback function that is used BEFORE stepping the system. Use it to apply forces, for example. Inside the function, "this" will refer to this Body object.
  6116. * @property preStep
  6117. * @type {Function}
  6118. * @deprecated Use World events instead
  6119. */
  6120. this.preStep = null;
  6121. /**
  6122. * Callback function that is used AFTER stepping the system. Inside the function, "this" will refer to this Body object.
  6123. * @property postStep
  6124. * @type {Function}
  6125. * @deprecated Use World events instead
  6126. */
  6127. this.postStep = null;
  6128. this.vlambda = new Vec3();
  6129. /**
  6130. * @property {Number} collisionFilterGroup
  6131. */
  6132. this.collisionFilterGroup = typeof(options.collisionFilterGroup) === 'number' ? options.collisionFilterGroup : 1;
  6133. /**
  6134. * @property {Number} collisionFilterMask
  6135. */
  6136. this.collisionFilterMask = typeof(options.collisionFilterMask) === 'number' ? options.collisionFilterMask : 1;
  6137. /**
  6138. * Whether to produce contact forces when in contact with other bodies. Note that contacts will be generated, but they will be disabled.
  6139. * @property {Number} collisionResponse
  6140. */
  6141. this.collisionResponse = true;
  6142. /**
  6143. * @property position
  6144. * @type {Vec3}
  6145. */
  6146. this.position = new Vec3();
  6147. /**
  6148. * @property {Vec3} previousPosition
  6149. */
  6150. this.previousPosition = new Vec3();
  6151. /**
  6152. * Interpolated position of the body.
  6153. * @property {Vec3} interpolatedPosition
  6154. */
  6155. this.interpolatedPosition = new Vec3();
  6156. /**
  6157. * Initial position of the body
  6158. * @property initPosition
  6159. * @type {Vec3}
  6160. */
  6161. this.initPosition = new Vec3();
  6162. if(options.position){
  6163. this.position.copy(options.position);
  6164. this.previousPosition.copy(options.position);
  6165. this.interpolatedPosition.copy(options.position);
  6166. this.initPosition.copy(options.position);
  6167. }
  6168. /**
  6169. * @property velocity
  6170. * @type {Vec3}
  6171. */
  6172. this.velocity = new Vec3();
  6173. if(options.velocity){
  6174. this.velocity.copy(options.velocity);
  6175. }
  6176. /**
  6177. * @property initVelocity
  6178. * @type {Vec3}
  6179. */
  6180. this.initVelocity = new Vec3();
  6181. /**
  6182. * Linear force on the body
  6183. * @property force
  6184. * @type {Vec3}
  6185. */
  6186. this.force = new Vec3();
  6187. var mass = typeof(options.mass) === 'number' ? options.mass : 0;
  6188. /**
  6189. * @property mass
  6190. * @type {Number}
  6191. * @default 0
  6192. */
  6193. this.mass = mass;
  6194. /**
  6195. * @property invMass
  6196. * @type {Number}
  6197. */
  6198. this.invMass = mass > 0 ? 1.0 / mass : 0;
  6199. /**
  6200. * @property material
  6201. * @type {Material}
  6202. */
  6203. this.material = options.material || null;
  6204. /**
  6205. * @property linearDamping
  6206. * @type {Number}
  6207. */
  6208. this.linearDamping = typeof(options.linearDamping) === 'number' ? options.linearDamping : 0.01;
  6209. /**
  6210. * One of: Body.DYNAMIC, Body.STATIC and Body.KINEMATIC.
  6211. * @property type
  6212. * @type {Number}
  6213. */
  6214. this.type = (mass <= 0.0 ? Body.STATIC : Body.DYNAMIC);
  6215. if(typeof(options.type) === typeof(Body.STATIC)){
  6216. this.type = options.type;
  6217. }
  6218. /**
  6219. * If true, the body will automatically fall to sleep.
  6220. * @property allowSleep
  6221. * @type {Boolean}
  6222. * @default true
  6223. */
  6224. this.allowSleep = typeof(options.allowSleep) !== 'undefined' ? options.allowSleep : true;
  6225. /**
  6226. * Current sleep state.
  6227. * @property sleepState
  6228. * @type {Number}
  6229. */
  6230. this.sleepState = 0;
  6231. /**
  6232. * If the speed (the norm of the velocity) is smaller than this value, the body is considered sleepy.
  6233. * @property sleepSpeedLimit
  6234. * @type {Number}
  6235. * @default 0.1
  6236. */
  6237. this.sleepSpeedLimit = typeof(options.sleepSpeedLimit) !== 'undefined' ? options.sleepSpeedLimit : 0.1;
  6238. /**
  6239. * If the body has been sleepy for this sleepTimeLimit seconds, it is considered sleeping.
  6240. * @property sleepTimeLimit
  6241. * @type {Number}
  6242. * @default 1
  6243. */
  6244. this.sleepTimeLimit = typeof(options.sleepTimeLimit) !== 'undefined' ? options.sleepTimeLimit : 1;
  6245. this.timeLastSleepy = 0;
  6246. this._wakeUpAfterNarrowphase = false;
  6247. /**
  6248. * Rotational force on the body, around center of mass
  6249. * @property {Vec3} torque
  6250. */
  6251. this.torque = new Vec3();
  6252. /**
  6253. * Orientation of the body
  6254. * @property quaternion
  6255. * @type {Quaternion}
  6256. */
  6257. this.quaternion = new Quaternion();
  6258. /**
  6259. * @property initQuaternion
  6260. * @type {Quaternion}
  6261. */
  6262. this.initQuaternion = new Quaternion();
  6263. /**
  6264. * @property {Quaternion} previousQuaternion
  6265. */
  6266. this.previousQuaternion = new Quaternion();
  6267. /**
  6268. * Interpolated orientation of the body.
  6269. * @property {Quaternion} interpolatedQuaternion
  6270. */
  6271. this.interpolatedQuaternion = new Quaternion();
  6272. if(options.quaternion){
  6273. this.quaternion.copy(options.quaternion);
  6274. this.initQuaternion.copy(options.quaternion);
  6275. this.previousQuaternion.copy(options.quaternion);
  6276. this.interpolatedQuaternion.copy(options.quaternion);
  6277. }
  6278. /**
  6279. * @property angularVelocity
  6280. * @type {Vec3}
  6281. */
  6282. this.angularVelocity = new Vec3();
  6283. if(options.angularVelocity){
  6284. this.angularVelocity.copy(options.angularVelocity);
  6285. }
  6286. /**
  6287. * @property initAngularVelocity
  6288. * @type {Vec3}
  6289. */
  6290. this.initAngularVelocity = new Vec3();
  6291. /**
  6292. * @property shapes
  6293. * @type {array}
  6294. */
  6295. this.shapes = [];
  6296. /**
  6297. * @property shapeOffsets
  6298. * @type {array}
  6299. */
  6300. this.shapeOffsets = [];
  6301. /**
  6302. * @property shapeOrientations
  6303. * @type {array}
  6304. */
  6305. this.shapeOrientations = [];
  6306. /**
  6307. * @property inertia
  6308. * @type {Vec3}
  6309. */
  6310. this.inertia = new Vec3();
  6311. /**
  6312. * @property {Vec3} invInertia
  6313. */
  6314. this.invInertia = new Vec3();
  6315. /**
  6316. * @property {Mat3} invInertiaWorld
  6317. */
  6318. this.invInertiaWorld = new Mat3();
  6319. this.invMassSolve = 0;
  6320. /**
  6321. * @property {Vec3} invInertiaSolve
  6322. */
  6323. this.invInertiaSolve = new Vec3();
  6324. /**
  6325. * @property {Mat3} invInertiaWorldSolve
  6326. */
  6327. this.invInertiaWorldSolve = new Mat3();
  6328. /**
  6329. * Set to true if you don't want the body to rotate. Make sure to run .updateMassProperties() after changing this.
  6330. * @property {Boolean} fixedRotation
  6331. * @default false
  6332. */
  6333. this.fixedRotation = typeof(options.fixedRotation) !== "undefined" ? options.fixedRotation : false;
  6334. /**
  6335. * @property {Number} angularDamping
  6336. */
  6337. this.angularDamping = typeof(options.angularDamping) !== 'undefined' ? options.angularDamping : 0.01;
  6338. /**
  6339. * @property {Vec3} linearFactor
  6340. */
  6341. this.linearFactor = new Vec3(1,1,1);
  6342. if(options.linearFactor){
  6343. this.linearFactor.copy(options.linearFactor);
  6344. }
  6345. /**
  6346. * @property {Vec3} angularFactor
  6347. */
  6348. this.angularFactor = new Vec3(1,1,1);
  6349. if(options.angularFactor){
  6350. this.angularFactor.copy(options.angularFactor);
  6351. }
  6352. /**
  6353. * @property aabb
  6354. * @type {AABB}
  6355. */
  6356. this.aabb = new AABB();
  6357. /**
  6358. * Indicates if the AABB needs to be updated before use.
  6359. * @property aabbNeedsUpdate
  6360. * @type {Boolean}
  6361. */
  6362. this.aabbNeedsUpdate = true;
  6363. this.wlambda = new Vec3();
  6364. if(options.shape){
  6365. this.addShape(options.shape);
  6366. }
  6367. this.updateMassProperties();
  6368. }
  6369. Body.prototype = new EventTarget();
  6370. Body.prototype.constructor = Body;
  6371. /**
  6372. * Dispatched after two bodies collide. This event is dispatched on each
  6373. * of the two bodies involved in the collision.
  6374. * @event collide
  6375. * @param {Body} body The body that was involved in the collision.
  6376. * @param {ContactEquation} contact The details of the collision.
  6377. */
  6378. Body.COLLIDE_EVENT_NAME = "collide";
  6379. /**
  6380. * A dynamic body is fully simulated. Can be moved manually by the user, but normally they move according to forces. A dynamic body can collide with all body types. A dynamic body always has finite, non-zero mass.
  6381. * @static
  6382. * @property DYNAMIC
  6383. * @type {Number}
  6384. */
  6385. Body.DYNAMIC = 1;
  6386. /**
  6387. * A static body does not move during simulation and behaves as if it has infinite mass. Static bodies can be moved manually by setting the position of the body. The velocity of a static body is always zero. Static bodies do not collide with other static or kinematic bodies.
  6388. * @static
  6389. * @property STATIC
  6390. * @type {Number}
  6391. */
  6392. Body.STATIC = 2;
  6393. /**
  6394. * A kinematic body moves under simulation according to its velocity. They do not respond to forces. They can be moved manually, but normally a kinematic body is moved by setting its velocity. A kinematic body behaves as if it has infinite mass. Kinematic bodies do not collide with other static or kinematic bodies.
  6395. * @static
  6396. * @property KINEMATIC
  6397. * @type {Number}
  6398. */
  6399. Body.KINEMATIC = 4;
  6400. /**
  6401. * @static
  6402. * @property AWAKE
  6403. * @type {number}
  6404. */
  6405. Body.AWAKE = 0;
  6406. /**
  6407. * @static
  6408. * @property SLEEPY
  6409. * @type {number}
  6410. */
  6411. Body.SLEEPY = 1;
  6412. /**
  6413. * @static
  6414. * @property SLEEPING
  6415. * @type {number}
  6416. */
  6417. Body.SLEEPING = 2;
  6418. Body.idCounter = 0;
  6419. /**
  6420. * Dispatched after a sleeping body has woken up.
  6421. * @event wakeup
  6422. */
  6423. Body.wakeupEvent = {
  6424. type: "wakeup"
  6425. };
  6426. /**
  6427. * Wake the body up.
  6428. * @method wakeUp
  6429. */
  6430. Body.prototype.wakeUp = function(){
  6431. var s = this.sleepState;
  6432. this.sleepState = 0;
  6433. this._wakeUpAfterNarrowphase = false;
  6434. if(s === Body.SLEEPING){
  6435. this.dispatchEvent(Body.wakeupEvent);
  6436. }
  6437. };
  6438. /**
  6439. * Force body sleep
  6440. * @method sleep
  6441. */
  6442. Body.prototype.sleep = function(){
  6443. this.sleepState = Body.SLEEPING;
  6444. this.velocity.set(0,0,0);
  6445. this.angularVelocity.set(0,0,0);
  6446. this._wakeUpAfterNarrowphase = false;
  6447. };
  6448. /**
  6449. * Dispatched after a body has gone in to the sleepy state.
  6450. * @event sleepy
  6451. */
  6452. Body.sleepyEvent = {
  6453. type: "sleepy"
  6454. };
  6455. /**
  6456. * Dispatched after a body has fallen asleep.
  6457. * @event sleep
  6458. */
  6459. Body.sleepEvent = {
  6460. type: "sleep"
  6461. };
  6462. /**
  6463. * Called every timestep to update internal sleep timer and change sleep state if needed.
  6464. * @method sleepTick
  6465. * @param {Number} time The world time in seconds
  6466. */
  6467. Body.prototype.sleepTick = function(time){
  6468. if(this.allowSleep){
  6469. var sleepState = this.sleepState;
  6470. var speedSquared = this.velocity.norm2() + this.angularVelocity.norm2();
  6471. var speedLimitSquared = Math.pow(this.sleepSpeedLimit,2);
  6472. if(sleepState===Body.AWAKE && speedSquared < speedLimitSquared){
  6473. this.sleepState = Body.SLEEPY; // Sleepy
  6474. this.timeLastSleepy = time;
  6475. this.dispatchEvent(Body.sleepyEvent);
  6476. } else if(sleepState===Body.SLEEPY && speedSquared > speedLimitSquared){
  6477. this.wakeUp(); // Wake up
  6478. } else if(sleepState===Body.SLEEPY && (time - this.timeLastSleepy ) > this.sleepTimeLimit){
  6479. this.sleep(); // Sleeping
  6480. this.dispatchEvent(Body.sleepEvent);
  6481. }
  6482. }
  6483. };
  6484. /**
  6485. * If the body is sleeping, it should be immovable / have infinite mass during solve. We solve it by having a separate "solve mass".
  6486. * @method updateSolveMassProperties
  6487. */
  6488. Body.prototype.updateSolveMassProperties = function(){
  6489. if(this.sleepState === Body.SLEEPING || this.type === Body.KINEMATIC){
  6490. this.invMassSolve = 0;
  6491. this.invInertiaSolve.setZero();
  6492. this.invInertiaWorldSolve.setZero();
  6493. } else {
  6494. this.invMassSolve = this.invMass;
  6495. this.invInertiaSolve.copy(this.invInertia);
  6496. this.invInertiaWorldSolve.copy(this.invInertiaWorld);
  6497. }
  6498. };
  6499. /**
  6500. * Convert a world point to local body frame.
  6501. * @method pointToLocalFrame
  6502. * @param {Vec3} worldPoint
  6503. * @param {Vec3} result
  6504. * @return {Vec3}
  6505. */
  6506. Body.prototype.pointToLocalFrame = function(worldPoint,result){
  6507. var result = result || new Vec3();
  6508. worldPoint.vsub(this.position,result);
  6509. this.quaternion.conjugate().vmult(result,result);
  6510. return result;
  6511. };
  6512. /**
  6513. * Convert a world vector to local body frame.
  6514. * @method vectorToLocalFrame
  6515. * @param {Vec3} worldPoint
  6516. * @param {Vec3} result
  6517. * @return {Vec3}
  6518. */
  6519. Body.prototype.vectorToLocalFrame = function(worldVector, result){
  6520. var result = result || new Vec3();
  6521. this.quaternion.conjugate().vmult(worldVector,result);
  6522. return result;
  6523. };
  6524. /**
  6525. * Convert a local body point to world frame.
  6526. * @method pointToWorldFrame
  6527. * @param {Vec3} localPoint
  6528. * @param {Vec3} result
  6529. * @return {Vec3}
  6530. */
  6531. Body.prototype.pointToWorldFrame = function(localPoint,result){
  6532. var result = result || new Vec3();
  6533. this.quaternion.vmult(localPoint,result);
  6534. result.vadd(this.position,result);
  6535. return result;
  6536. };
  6537. /**
  6538. * Convert a local body point to world frame.
  6539. * @method vectorToWorldFrame
  6540. * @param {Vec3} localVector
  6541. * @param {Vec3} result
  6542. * @return {Vec3}
  6543. */
  6544. Body.prototype.vectorToWorldFrame = function(localVector, result){
  6545. var result = result || new Vec3();
  6546. this.quaternion.vmult(localVector, result);
  6547. return result;
  6548. };
  6549. var tmpVec = new Vec3();
  6550. var tmpQuat = new Quaternion();
  6551. /**
  6552. * Add a shape to the body with a local offset and orientation.
  6553. * @method addShape
  6554. * @param {Shape} shape
  6555. * @param {Vec3} [_offset]
  6556. * @param {Quaternion} [_orientation]
  6557. * @return {Body} The body object, for chainability.
  6558. */
  6559. Body.prototype.addShape = function(shape, _offset, _orientation){
  6560. var offset = new Vec3();
  6561. var orientation = new Quaternion();
  6562. if(_offset){
  6563. offset.copy(_offset);
  6564. }
  6565. if(_orientation){
  6566. orientation.copy(_orientation);
  6567. }
  6568. this.shapes.push(shape);
  6569. this.shapeOffsets.push(offset);
  6570. this.shapeOrientations.push(orientation);
  6571. this.updateMassProperties();
  6572. this.updateBoundingRadius();
  6573. this.aabbNeedsUpdate = true;
  6574. shape.body = this;
  6575. return this;
  6576. };
  6577. /**
  6578. * Update the bounding radius of the body. Should be done if any of the shapes are changed.
  6579. * @method updateBoundingRadius
  6580. */
  6581. Body.prototype.updateBoundingRadius = function(){
  6582. var shapes = this.shapes,
  6583. shapeOffsets = this.shapeOffsets,
  6584. N = shapes.length,
  6585. radius = 0;
  6586. for(var i=0; i!==N; i++){
  6587. var shape = shapes[i];
  6588. shape.updateBoundingSphereRadius();
  6589. var offset = shapeOffsets[i].norm(),
  6590. r = shape.boundingSphereRadius;
  6591. if(offset + r > radius){
  6592. radius = offset + r;
  6593. }
  6594. }
  6595. this.boundingRadius = radius;
  6596. };
  6597. var computeAABB_shapeAABB = new AABB();
  6598. /**
  6599. * Updates the .aabb
  6600. * @method computeAABB
  6601. * @todo rename to updateAABB()
  6602. */
  6603. Body.prototype.computeAABB = function(){
  6604. var shapes = this.shapes,
  6605. shapeOffsets = this.shapeOffsets,
  6606. shapeOrientations = this.shapeOrientations,
  6607. N = shapes.length,
  6608. offset = tmpVec,
  6609. orientation = tmpQuat,
  6610. bodyQuat = this.quaternion,
  6611. aabb = this.aabb,
  6612. shapeAABB = computeAABB_shapeAABB;
  6613. for(var i=0; i!==N; i++){
  6614. var shape = shapes[i];
  6615. // Get shape world position
  6616. bodyQuat.vmult(shapeOffsets[i], offset);
  6617. offset.vadd(this.position, offset);
  6618. // Get shape world quaternion
  6619. shapeOrientations[i].mult(bodyQuat, orientation);
  6620. // Get shape AABB
  6621. shape.calculateWorldAABB(offset, orientation, shapeAABB.lowerBound, shapeAABB.upperBound);
  6622. if(i === 0){
  6623. aabb.copy(shapeAABB);
  6624. } else {
  6625. aabb.extend(shapeAABB);
  6626. }
  6627. }
  6628. this.aabbNeedsUpdate = false;
  6629. };
  6630. var uiw_m1 = new Mat3(),
  6631. uiw_m2 = new Mat3(),
  6632. uiw_m3 = new Mat3();
  6633. /**
  6634. * Update .inertiaWorld and .invInertiaWorld
  6635. * @method updateInertiaWorld
  6636. */
  6637. Body.prototype.updateInertiaWorld = function(force){
  6638. var I = this.invInertia;
  6639. if (I.x === I.y && I.y === I.z && !force) {
  6640. // If inertia M = s*I, where I is identity and s a scalar, then
  6641. // R*M*R' = R*(s*I)*R' = s*R*I*R' = s*R*R' = s*I = M
  6642. // where R is the rotation matrix.
  6643. // In other words, we don't have to transform the inertia if all
  6644. // inertia diagonal entries are equal.
  6645. } else {
  6646. var m1 = uiw_m1,
  6647. m2 = uiw_m2,
  6648. m3 = uiw_m3;
  6649. m1.setRotationFromQuaternion(this.quaternion);
  6650. m1.transpose(m2);
  6651. m1.scale(I,m1);
  6652. m1.mmult(m2,this.invInertiaWorld);
  6653. }
  6654. };
  6655. /**
  6656. * Apply force to a world point. This could for example be a point on the Body surface. Applying force this way will add to Body.force and Body.torque.
  6657. * @method applyForce
  6658. * @param {Vec3} force The amount of force to add.
  6659. * @param {Vec3} relativePoint A point relative to the center of mass to apply the force on.
  6660. */
  6661. var Body_applyForce_r = new Vec3();
  6662. var Body_applyForce_rotForce = new Vec3();
  6663. Body.prototype.applyForce = function(force,relativePoint){
  6664. if(this.type !== Body.DYNAMIC){ // Needed?
  6665. return;
  6666. }
  6667. // Compute produced rotational force
  6668. var rotForce = Body_applyForce_rotForce;
  6669. relativePoint.cross(force,rotForce);
  6670. // Add linear force
  6671. this.force.vadd(force,this.force);
  6672. // Add rotational force
  6673. this.torque.vadd(rotForce,this.torque);
  6674. };
  6675. /**
  6676. * Apply force to a local point in the body.
  6677. * @method applyLocalForce
  6678. * @param {Vec3} force The force vector to apply, defined locally in the body frame.
  6679. * @param {Vec3} localPoint A local point in the body to apply the force on.
  6680. */
  6681. var Body_applyLocalForce_worldForce = new Vec3();
  6682. var Body_applyLocalForce_relativePointWorld = new Vec3();
  6683. Body.prototype.applyLocalForce = function(localForce, localPoint){
  6684. if(this.type !== Body.DYNAMIC){
  6685. return;
  6686. }
  6687. var worldForce = Body_applyLocalForce_worldForce;
  6688. var relativePointWorld = Body_applyLocalForce_relativePointWorld;
  6689. // Transform the force vector to world space
  6690. this.vectorToWorldFrame(localForce, worldForce);
  6691. this.vectorToWorldFrame(localPoint, relativePointWorld);
  6692. this.applyForce(worldForce, relativePointWorld);
  6693. };
  6694. /**
  6695. * Apply impulse to a world point. This could for example be a point on the Body surface. An impulse is a force added to a body during a short period of time (impulse = force * time). Impulses will be added to Body.velocity and Body.angularVelocity.
  6696. * @method applyImpulse
  6697. * @param {Vec3} impulse The amount of impulse to add.
  6698. * @param {Vec3} relativePoint A point relative to the center of mass to apply the force on.
  6699. */
  6700. var Body_applyImpulse_r = new Vec3();
  6701. var Body_applyImpulse_velo = new Vec3();
  6702. var Body_applyImpulse_rotVelo = new Vec3();
  6703. Body.prototype.applyImpulse = function(impulse, relativePoint){
  6704. if(this.type !== Body.DYNAMIC){
  6705. return;
  6706. }
  6707. // Compute point position relative to the body center
  6708. var r = relativePoint;
  6709. // Compute produced central impulse velocity
  6710. var velo = Body_applyImpulse_velo;
  6711. velo.copy(impulse);
  6712. velo.mult(this.invMass,velo);
  6713. // Add linear impulse
  6714. this.velocity.vadd(velo, this.velocity);
  6715. // Compute produced rotational impulse velocity
  6716. var rotVelo = Body_applyImpulse_rotVelo;
  6717. r.cross(impulse,rotVelo);
  6718. /*
  6719. rotVelo.x *= this.invInertia.x;
  6720. rotVelo.y *= this.invInertia.y;
  6721. rotVelo.z *= this.invInertia.z;
  6722. */
  6723. this.invInertiaWorld.vmult(rotVelo,rotVelo);
  6724. // Add rotational Impulse
  6725. this.angularVelocity.vadd(rotVelo, this.angularVelocity);
  6726. };
  6727. /**
  6728. * Apply locally-defined impulse to a local point in the body.
  6729. * @method applyLocalImpulse
  6730. * @param {Vec3} force The force vector to apply, defined locally in the body frame.
  6731. * @param {Vec3} localPoint A local point in the body to apply the force on.
  6732. */
  6733. var Body_applyLocalImpulse_worldImpulse = new Vec3();
  6734. var Body_applyLocalImpulse_relativePoint = new Vec3();
  6735. Body.prototype.applyLocalImpulse = function(localImpulse, localPoint){
  6736. if(this.type !== Body.DYNAMIC){
  6737. return;
  6738. }
  6739. var worldImpulse = Body_applyLocalImpulse_worldImpulse;
  6740. var relativePointWorld = Body_applyLocalImpulse_relativePoint;
  6741. // Transform the force vector to world space
  6742. this.vectorToWorldFrame(localImpulse, worldImpulse);
  6743. this.vectorToWorldFrame(localPoint, relativePointWorld);
  6744. this.applyImpulse(worldImpulse, relativePointWorld);
  6745. };
  6746. var Body_updateMassProperties_halfExtents = new Vec3();
  6747. /**
  6748. * Should be called whenever you change the body shape or mass.
  6749. * @method updateMassProperties
  6750. */
  6751. Body.prototype.updateMassProperties = function(){
  6752. var halfExtents = Body_updateMassProperties_halfExtents;
  6753. this.invMass = this.mass > 0 ? 1.0 / this.mass : 0;
  6754. var I = this.inertia;
  6755. var fixed = this.fixedRotation;
  6756. // Approximate with AABB box
  6757. this.computeAABB();
  6758. halfExtents.set(
  6759. (this.aabb.upperBound.x-this.aabb.lowerBound.x) / 2,
  6760. (this.aabb.upperBound.y-this.aabb.lowerBound.y) / 2,
  6761. (this.aabb.upperBound.z-this.aabb.lowerBound.z) / 2
  6762. );
  6763. Box.calculateInertia(halfExtents, this.mass, I);
  6764. this.invInertia.set(
  6765. I.x > 0 && !fixed ? 1.0 / I.x : 0,
  6766. I.y > 0 && !fixed ? 1.0 / I.y : 0,
  6767. I.z > 0 && !fixed ? 1.0 / I.z : 0
  6768. );
  6769. this.updateInertiaWorld(true);
  6770. };
  6771. /**
  6772. * Get world velocity of a point in the body.
  6773. * @method getVelocityAtWorldPoint
  6774. * @param {Vec3} worldPoint
  6775. * @param {Vec3} result
  6776. * @return {Vec3} The result vector.
  6777. */
  6778. Body.prototype.getVelocityAtWorldPoint = function(worldPoint, result){
  6779. var r = new Vec3();
  6780. worldPoint.vsub(this.position, r);
  6781. this.angularVelocity.cross(r, result);
  6782. this.velocity.vadd(result, result);
  6783. return result;
  6784. };
  6785. var torque = new Vec3();
  6786. var invI_tau_dt = new Vec3();
  6787. var w = new Quaternion();
  6788. var wq = new Quaternion();
  6789. /**
  6790. * Move the body forward in time.
  6791. * @param {number} dt Time step
  6792. * @param {boolean} quatNormalize Set to true to normalize the body quaternion
  6793. * @param {boolean} quatNormalizeFast If the quaternion should be normalized using "fast" quaternion normalization
  6794. */
  6795. Body.prototype.integrate = function(dt, quatNormalize, quatNormalizeFast){
  6796. // Save previous position
  6797. this.previousPosition.copy(this.position);
  6798. this.previousQuaternion.copy(this.quaternion);
  6799. if(!(this.type === Body.DYNAMIC || this.type === Body.KINEMATIC) || this.sleepState === Body.SLEEPING){ // Only for dynamic
  6800. return;
  6801. }
  6802. var velo = this.velocity,
  6803. angularVelo = this.angularVelocity,
  6804. pos = this.position,
  6805. force = this.force,
  6806. torque = this.torque,
  6807. quat = this.quaternion,
  6808. invMass = this.invMass,
  6809. invInertia = this.invInertiaWorld,
  6810. linearFactor = this.linearFactor;
  6811. var iMdt = invMass * dt;
  6812. velo.x += force.x * iMdt * linearFactor.x;
  6813. velo.y += force.y * iMdt * linearFactor.y;
  6814. velo.z += force.z * iMdt * linearFactor.z;
  6815. var e = invInertia.elements;
  6816. var angularFactor = this.angularFactor;
  6817. var tx = torque.x * angularFactor.x;
  6818. var ty = torque.y * angularFactor.y;
  6819. var tz = torque.z * angularFactor.z;
  6820. angularVelo.x += dt * (e[0] * tx + e[1] * ty + e[2] * tz);
  6821. angularVelo.y += dt * (e[3] * tx + e[4] * ty + e[5] * tz);
  6822. angularVelo.z += dt * (e[6] * tx + e[7] * ty + e[8] * tz);
  6823. // Use new velocity - leap frog
  6824. pos.x += velo.x * dt;
  6825. pos.y += velo.y * dt;
  6826. pos.z += velo.z * dt;
  6827. quat.integrate(this.angularVelocity, dt, this.angularFactor, quat);
  6828. if(quatNormalize){
  6829. if(quatNormalizeFast){
  6830. quat.normalizeFast();
  6831. } else {
  6832. quat.normalize();
  6833. }
  6834. }
  6835. this.aabbNeedsUpdate = true;
  6836. // Update world inertia
  6837. this.updateInertiaWorld();
  6838. };
  6839. },{"../collision/AABB":18,"../material/Material":41,"../math/Mat3":43,"../math/Quaternion":44,"../math/Vec3":46,"../shapes/Box":53,"../shapes/Shape":59,"../utils/EventTarget":65}],48:[function(require,module,exports){
  6840. var Body = require('./Body');
  6841. var Vec3 = require('../math/Vec3');
  6842. var Quaternion = require('../math/Quaternion');
  6843. var RaycastResult = require('../collision/RaycastResult');
  6844. var Ray = require('../collision/Ray');
  6845. var WheelInfo = require('../objects/WheelInfo');
  6846. module.exports = RaycastVehicle;
  6847. /**
  6848. * Vehicle helper class that casts rays from the wheel positions towards the ground and applies forces.
  6849. * @class RaycastVehicle
  6850. * @constructor
  6851. * @param {object} [options]
  6852. * @param {Body} [options.chassisBody] The car chassis body.
  6853. * @param {integer} [options.indexRightAxis] Axis to use for right. x=0, y=1, z=2
  6854. * @param {integer} [options.indexLeftAxis]
  6855. * @param {integer} [options.indexUpAxis]
  6856. */
  6857. function RaycastVehicle(options){
  6858. /**
  6859. * @property {Body} chassisBody
  6860. */
  6861. this.chassisBody = options.chassisBody;
  6862. /**
  6863. * An array of WheelInfo objects.
  6864. * @property {array} wheelInfos
  6865. */
  6866. this.wheelInfos = [];
  6867. /**
  6868. * Will be set to true if the car is sliding.
  6869. * @property {boolean} sliding
  6870. */
  6871. this.sliding = false;
  6872. /**
  6873. * @property {World} world
  6874. */
  6875. this.world = null;
  6876. /**
  6877. * Index of the right axis, 0=x, 1=y, 2=z
  6878. * @property {integer} indexRightAxis
  6879. * @default 1
  6880. */
  6881. this.indexRightAxis = typeof(options.indexRightAxis) !== 'undefined' ? options.indexRightAxis : 1;
  6882. /**
  6883. * Index of the forward axis, 0=x, 1=y, 2=z
  6884. * @property {integer} indexForwardAxis
  6885. * @default 0
  6886. */
  6887. this.indexForwardAxis = typeof(options.indexForwardAxis) !== 'undefined' ? options.indexForwardAxis : 0;
  6888. /**
  6889. * Index of the up axis, 0=x, 1=y, 2=z
  6890. * @property {integer} indexUpAxis
  6891. * @default 2
  6892. */
  6893. this.indexUpAxis = typeof(options.indexUpAxis) !== 'undefined' ? options.indexUpAxis : 2;
  6894. }
  6895. var tmpVec1 = new Vec3();
  6896. var tmpVec2 = new Vec3();
  6897. var tmpVec3 = new Vec3();
  6898. var tmpVec4 = new Vec3();
  6899. var tmpVec5 = new Vec3();
  6900. var tmpVec6 = new Vec3();
  6901. var tmpRay = new Ray();
  6902. /**
  6903. * Add a wheel. For information about the options, see WheelInfo.
  6904. * @method addWheel
  6905. * @param {object} [options]
  6906. */
  6907. RaycastVehicle.prototype.addWheel = function(options){
  6908. options = options || {};
  6909. var info = new WheelInfo(options);
  6910. var index = this.wheelInfos.length;
  6911. this.wheelInfos.push(info);
  6912. return index;
  6913. };
  6914. /**
  6915. * Set the steering value of a wheel.
  6916. * @method setSteeringValue
  6917. * @param {number} value
  6918. * @param {integer} wheelIndex
  6919. */
  6920. RaycastVehicle.prototype.setSteeringValue = function(value, wheelIndex){
  6921. var wheel = this.wheelInfos[wheelIndex];
  6922. wheel.steering = value;
  6923. };
  6924. var torque = new Vec3();
  6925. /**
  6926. * Set the wheel force to apply on one of the wheels each time step
  6927. * @method applyEngineForce
  6928. * @param {number} value
  6929. * @param {integer} wheelIndex
  6930. */
  6931. RaycastVehicle.prototype.applyEngineForce = function(value, wheelIndex){
  6932. this.wheelInfos[wheelIndex].engineForce = value;
  6933. };
  6934. /**
  6935. * Set the braking force of a wheel
  6936. * @method setBrake
  6937. * @param {number} brake
  6938. * @param {integer} wheelIndex
  6939. */
  6940. RaycastVehicle.prototype.setBrake = function(brake, wheelIndex){
  6941. this.wheelInfos[wheelIndex].brake = brake;
  6942. };
  6943. /**
  6944. * Add the vehicle including its constraints to the world.
  6945. * @method addToWorld
  6946. * @param {World} world
  6947. */
  6948. RaycastVehicle.prototype.addToWorld = function(world){
  6949. var constraints = this.constraints;
  6950. world.addBody(this.chassisBody);
  6951. var that = this;
  6952. this.preStepCallback = function(){
  6953. that.updateVehicle(world.dt);
  6954. };
  6955. world.addEventListener('preStep', this.preStepCallback);
  6956. this.world = world;
  6957. };
  6958. /**
  6959. * Get one of the wheel axles, world-oriented.
  6960. * @private
  6961. * @method getVehicleAxisWorld
  6962. * @param {integer} axisIndex
  6963. * @param {Vec3} result
  6964. */
  6965. RaycastVehicle.prototype.getVehicleAxisWorld = function(axisIndex, result){
  6966. result.set(
  6967. axisIndex === 0 ? 1 : 0,
  6968. axisIndex === 1 ? 1 : 0,
  6969. axisIndex === 2 ? 1 : 0
  6970. );
  6971. this.chassisBody.vectorToWorldFrame(result, result);
  6972. };
  6973. RaycastVehicle.prototype.updateVehicle = function(timeStep){
  6974. var wheelInfos = this.wheelInfos;
  6975. var numWheels = wheelInfos.length;
  6976. var chassisBody = this.chassisBody;
  6977. for (var i = 0; i < numWheels; i++) {
  6978. this.updateWheelTransform(i);
  6979. }
  6980. this.currentVehicleSpeedKmHour = 3.6 * chassisBody.velocity.norm();
  6981. var forwardWorld = new Vec3();
  6982. this.getVehicleAxisWorld(this.indexForwardAxis, forwardWorld);
  6983. if (forwardWorld.dot(chassisBody.velocity) < 0){
  6984. this.currentVehicleSpeedKmHour *= -1;
  6985. }
  6986. // simulate suspension
  6987. for (var i = 0; i < numWheels; i++) {
  6988. this.castRay(wheelInfos[i]);
  6989. }
  6990. this.updateSuspension(timeStep);
  6991. var impulse = new Vec3();
  6992. var relpos = new Vec3();
  6993. for (var i = 0; i < numWheels; i++) {
  6994. //apply suspension force
  6995. var wheel = wheelInfos[i];
  6996. var suspensionForce = wheel.suspensionForce;
  6997. if (suspensionForce > wheel.maxSuspensionForce) {
  6998. suspensionForce = wheel.maxSuspensionForce;
  6999. }
  7000. wheel.raycastResult.hitNormalWorld.scale(suspensionForce * timeStep, impulse);
  7001. wheel.raycastResult.hitPointWorld.vsub(chassisBody.position, relpos);
  7002. chassisBody.applyImpulse(impulse, relpos);
  7003. }
  7004. this.updateFriction(timeStep);
  7005. var hitNormalWorldScaledWithProj = new Vec3();
  7006. var fwd = new Vec3();
  7007. var vel = new Vec3();
  7008. for (i = 0; i < numWheels; i++) {
  7009. var wheel = wheelInfos[i];
  7010. //var relpos = new Vec3();
  7011. //wheel.chassisConnectionPointWorld.vsub(chassisBody.position, relpos);
  7012. chassisBody.getVelocityAtWorldPoint(wheel.chassisConnectionPointWorld, vel);
  7013. // Hack to get the rotation in the correct direction
  7014. var m = 1;
  7015. switch(this.indexUpAxis){
  7016. case 1:
  7017. m = -1;
  7018. break;
  7019. }
  7020. if (wheel.isInContact) {
  7021. this.getVehicleAxisWorld(this.indexForwardAxis, fwd);
  7022. var proj = fwd.dot(wheel.raycastResult.hitNormalWorld);
  7023. wheel.raycastResult.hitNormalWorld.scale(proj, hitNormalWorldScaledWithProj);
  7024. fwd.vsub(hitNormalWorldScaledWithProj, fwd);
  7025. var proj2 = fwd.dot(vel);
  7026. wheel.deltaRotation = m * proj2 * timeStep / wheel.radius;
  7027. }
  7028. if((wheel.sliding || !wheel.isInContact) && wheel.engineForce !== 0 && wheel.useCustomSlidingRotationalSpeed){
  7029. // Apply custom rotation when accelerating and sliding
  7030. wheel.deltaRotation = (wheel.engineForce > 0 ? 1 : -1) * wheel.customSlidingRotationalSpeed * timeStep;
  7031. }
  7032. // Lock wheels
  7033. if(Math.abs(wheel.brake) > Math.abs(wheel.engineForce)){
  7034. wheel.deltaRotation = 0;
  7035. }
  7036. wheel.rotation += wheel.deltaRotation; // Use the old value
  7037. wheel.deltaRotation *= 0.99; // damping of rotation when not in contact
  7038. }
  7039. };
  7040. RaycastVehicle.prototype.updateSuspension = function(deltaTime) {
  7041. var chassisBody = this.chassisBody;
  7042. var chassisMass = chassisBody.mass;
  7043. var wheelInfos = this.wheelInfos;
  7044. var numWheels = wheelInfos.length;
  7045. for (var w_it = 0; w_it < numWheels; w_it++){
  7046. var wheel = wheelInfos[w_it];
  7047. if (wheel.isInContact){
  7048. var force;
  7049. // Spring
  7050. var susp_length = wheel.suspensionRestLength;
  7051. var current_length = wheel.suspensionLength;
  7052. var length_diff = (susp_length - current_length);
  7053. force = wheel.suspensionStiffness * length_diff * wheel.clippedInvContactDotSuspension;
  7054. // Damper
  7055. var projected_rel_vel = wheel.suspensionRelativeVelocity;
  7056. var susp_damping;
  7057. if (projected_rel_vel < 0) {
  7058. susp_damping = wheel.dampingCompression;
  7059. } else {
  7060. susp_damping = wheel.dampingRelaxation;
  7061. }
  7062. force -= susp_damping * projected_rel_vel;
  7063. wheel.suspensionForce = force * chassisMass;
  7064. if (wheel.suspensionForce < 0) {
  7065. wheel.suspensionForce = 0;
  7066. }
  7067. } else {
  7068. wheel.suspensionForce = 0;
  7069. }
  7070. }
  7071. };
  7072. /**
  7073. * Remove the vehicle including its constraints from the world.
  7074. * @method removeFromWorld
  7075. * @param {World} world
  7076. */
  7077. RaycastVehicle.prototype.removeFromWorld = function(world){
  7078. var constraints = this.constraints;
  7079. world.remove(this.chassisBody);
  7080. world.removeEventListener('preStep', this.preStepCallback);
  7081. this.world = null;
  7082. };
  7083. var castRay_rayvector = new Vec3();
  7084. var castRay_target = new Vec3();
  7085. RaycastVehicle.prototype.castRay = function(wheel) {
  7086. var rayvector = castRay_rayvector;
  7087. var target = castRay_target;
  7088. this.updateWheelTransformWorld(wheel);
  7089. var chassisBody = this.chassisBody;
  7090. var depth = -1;
  7091. var raylen = wheel.suspensionRestLength + wheel.radius;
  7092. wheel.directionWorld.scale(raylen, rayvector);
  7093. var source = wheel.chassisConnectionPointWorld;
  7094. source.vadd(rayvector, target);
  7095. var raycastResult = wheel.raycastResult;
  7096. var param = 0;
  7097. raycastResult.reset();
  7098. // Turn off ray collision with the chassis temporarily
  7099. var oldState = chassisBody.collisionResponse;
  7100. chassisBody.collisionResponse = false;
  7101. // Cast ray against world
  7102. this.world.rayTest(source, target, raycastResult);
  7103. chassisBody.collisionResponse = oldState;
  7104. var object = raycastResult.body;
  7105. wheel.raycastResult.groundObject = 0;
  7106. if (object) {
  7107. depth = raycastResult.distance;
  7108. wheel.raycastResult.hitNormalWorld = raycastResult.hitNormalWorld;
  7109. wheel.isInContact = true;
  7110. var hitDistance = raycastResult.distance;
  7111. wheel.suspensionLength = hitDistance - wheel.radius;
  7112. // clamp on max suspension travel
  7113. var minSuspensionLength = wheel.suspensionRestLength - wheel.maxSuspensionTravel;
  7114. var maxSuspensionLength = wheel.suspensionRestLength + wheel.maxSuspensionTravel;
  7115. if (wheel.suspensionLength < minSuspensionLength) {
  7116. wheel.suspensionLength = minSuspensionLength;
  7117. }
  7118. if (wheel.suspensionLength > maxSuspensionLength) {
  7119. wheel.suspensionLength = maxSuspensionLength;
  7120. wheel.raycastResult.reset();
  7121. }
  7122. var denominator = wheel.raycastResult.hitNormalWorld.dot(wheel.directionWorld);
  7123. var chassis_velocity_at_contactPoint = new Vec3();
  7124. chassisBody.getVelocityAtWorldPoint(wheel.raycastResult.hitPointWorld, chassis_velocity_at_contactPoint);
  7125. var projVel = wheel.raycastResult.hitNormalWorld.dot( chassis_velocity_at_contactPoint );
  7126. if (denominator >= -0.1) {
  7127. wheel.suspensionRelativeVelocity = 0;
  7128. wheel.clippedInvContactDotSuspension = 1 / 0.1;
  7129. } else {
  7130. var inv = -1 / denominator;
  7131. wheel.suspensionRelativeVelocity = projVel * inv;
  7132. wheel.clippedInvContactDotSuspension = inv;
  7133. }
  7134. } else {
  7135. //put wheel info as in rest position
  7136. wheel.suspensionLength = wheel.suspensionRestLength + 0 * wheel.maxSuspensionTravel;
  7137. wheel.suspensionRelativeVelocity = 0.0;
  7138. wheel.directionWorld.scale(-1, wheel.raycastResult.hitNormalWorld);
  7139. wheel.clippedInvContactDotSuspension = 1.0;
  7140. }
  7141. return depth;
  7142. };
  7143. RaycastVehicle.prototype.updateWheelTransformWorld = function(wheel){
  7144. wheel.isInContact = false;
  7145. var chassisBody = this.chassisBody;
  7146. chassisBody.pointToWorldFrame(wheel.chassisConnectionPointLocal, wheel.chassisConnectionPointWorld);
  7147. chassisBody.vectorToWorldFrame(wheel.directionLocal, wheel.directionWorld);
  7148. chassisBody.vectorToWorldFrame(wheel.axleLocal, wheel.axleWorld);
  7149. };
  7150. /**
  7151. * Update one of the wheel transform.
  7152. * Note when rendering wheels: during each step, wheel transforms are updated BEFORE the chassis; ie. their position becomes invalid after the step. Thus when you render wheels, you must update wheel transforms before rendering them. See raycastVehicle demo for an example.
  7153. * @method updateWheelTransform
  7154. * @param {integer} wheelIndex The wheel index to update.
  7155. */
  7156. RaycastVehicle.prototype.updateWheelTransform = function(wheelIndex){
  7157. var up = tmpVec4;
  7158. var right = tmpVec5;
  7159. var fwd = tmpVec6;
  7160. var wheel = this.wheelInfos[wheelIndex];
  7161. this.updateWheelTransformWorld(wheel);
  7162. wheel.directionLocal.scale(-1, up);
  7163. right.copy(wheel.axleLocal);
  7164. up.cross(right, fwd);
  7165. fwd.normalize();
  7166. right.normalize();
  7167. // Rotate around steering over the wheelAxle
  7168. var steering = wheel.steering;
  7169. var steeringOrn = new Quaternion();
  7170. steeringOrn.setFromAxisAngle(up, steering);
  7171. var rotatingOrn = new Quaternion();
  7172. rotatingOrn.setFromAxisAngle(right, wheel.rotation);
  7173. // World rotation of the wheel
  7174. var q = wheel.worldTransform.quaternion;
  7175. this.chassisBody.quaternion.mult(steeringOrn, q);
  7176. q.mult(rotatingOrn, q);
  7177. q.normalize();
  7178. // world position of the wheel
  7179. var p = wheel.worldTransform.position;
  7180. p.copy(wheel.directionWorld);
  7181. p.scale(wheel.suspensionLength, p);
  7182. p.vadd(wheel.chassisConnectionPointWorld, p);
  7183. };
  7184. var directions = [
  7185. new Vec3(1, 0, 0),
  7186. new Vec3(0, 1, 0),
  7187. new Vec3(0, 0, 1)
  7188. ];
  7189. /**
  7190. * Get the world transform of one of the wheels
  7191. * @method getWheelTransformWorld
  7192. * @param {integer} wheelIndex
  7193. * @return {Transform}
  7194. */
  7195. RaycastVehicle.prototype.getWheelTransformWorld = function(wheelIndex) {
  7196. return this.wheelInfos[wheelIndex].worldTransform;
  7197. };
  7198. var updateFriction_surfNormalWS_scaled_proj = new Vec3();
  7199. var updateFriction_axle = [];
  7200. var updateFriction_forwardWS = [];
  7201. var sideFrictionStiffness2 = 1;
  7202. RaycastVehicle.prototype.updateFriction = function(timeStep) {
  7203. var surfNormalWS_scaled_proj = updateFriction_surfNormalWS_scaled_proj;
  7204. //calculate the impulse, so that the wheels don't move sidewards
  7205. var wheelInfos = this.wheelInfos;
  7206. var numWheels = wheelInfos.length;
  7207. var chassisBody = this.chassisBody;
  7208. var forwardWS = updateFriction_forwardWS;
  7209. var axle = updateFriction_axle;
  7210. var numWheelsOnGround = 0;
  7211. for (var i = 0; i < numWheels; i++) {
  7212. var wheel = wheelInfos[i];
  7213. var groundObject = wheel.raycastResult.body;
  7214. if (groundObject){
  7215. numWheelsOnGround++;
  7216. }
  7217. wheel.sideImpulse = 0;
  7218. wheel.forwardImpulse = 0;
  7219. if(!forwardWS[i]){
  7220. forwardWS[i] = new Vec3();
  7221. }
  7222. if(!axle[i]){
  7223. axle[i] = new Vec3();
  7224. }
  7225. }
  7226. for (var i = 0; i < numWheels; i++){
  7227. var wheel = wheelInfos[i];
  7228. var groundObject = wheel.raycastResult.body;
  7229. if (groundObject) {
  7230. var axlei = axle[i];
  7231. var wheelTrans = this.getWheelTransformWorld(i);
  7232. // Get world axle
  7233. wheelTrans.vectorToWorldFrame(directions[this.indexRightAxis], axlei);
  7234. var surfNormalWS = wheel.raycastResult.hitNormalWorld;
  7235. var proj = axlei.dot(surfNormalWS);
  7236. surfNormalWS.scale(proj, surfNormalWS_scaled_proj);
  7237. axlei.vsub(surfNormalWS_scaled_proj, axlei);
  7238. axlei.normalize();
  7239. surfNormalWS.cross(axlei, forwardWS[i]);
  7240. forwardWS[i].normalize();
  7241. wheel.sideImpulse = resolveSingleBilateral(
  7242. chassisBody,
  7243. wheel.raycastResult.hitPointWorld,
  7244. groundObject,
  7245. wheel.raycastResult.hitPointWorld,
  7246. axlei
  7247. );
  7248. wheel.sideImpulse *= sideFrictionStiffness2;
  7249. }
  7250. }
  7251. var sideFactor = 1;
  7252. var fwdFactor = 0.5;
  7253. this.sliding = false;
  7254. for (var i = 0; i < numWheels; i++) {
  7255. var wheel = wheelInfos[i];
  7256. var groundObject = wheel.raycastResult.body;
  7257. var rollingFriction = 0;
  7258. wheel.slipInfo = 1;
  7259. if (groundObject) {
  7260. var defaultRollingFrictionImpulse = 0;
  7261. var maxImpulse = wheel.brake ? wheel.brake : defaultRollingFrictionImpulse;
  7262. // btWheelContactPoint contactPt(chassisBody,groundObject,wheelInfraycastInfo.hitPointWorld,forwardWS[wheel],maxImpulse);
  7263. // rollingFriction = calcRollingFriction(contactPt);
  7264. rollingFriction = calcRollingFriction(chassisBody, groundObject, wheel.raycastResult.hitPointWorld, forwardWS[i], maxImpulse);
  7265. rollingFriction += wheel.engineForce * timeStep;
  7266. // rollingFriction = 0;
  7267. var factor = maxImpulse / rollingFriction;
  7268. wheel.slipInfo *= factor;
  7269. }
  7270. //switch between active rolling (throttle), braking and non-active rolling friction (nthrottle/break)
  7271. wheel.forwardImpulse = 0;
  7272. wheel.skidInfo = 1;
  7273. if (groundObject) {
  7274. wheel.skidInfo = 1;
  7275. var maximp = wheel.suspensionForce * timeStep * wheel.frictionSlip;
  7276. var maximpSide = maximp;
  7277. var maximpSquared = maximp * maximpSide;
  7278. wheel.forwardImpulse = rollingFriction;//wheelInfo.engineForce* timeStep;
  7279. var x = wheel.forwardImpulse * fwdFactor;
  7280. var y = wheel.sideImpulse * sideFactor;
  7281. var impulseSquared = x * x + y * y;
  7282. wheel.sliding = false;
  7283. if (impulseSquared > maximpSquared) {
  7284. this.sliding = true;
  7285. wheel.sliding = true;
  7286. var factor = maximp / Math.sqrt(impulseSquared);
  7287. wheel.skidInfo *= factor;
  7288. }
  7289. }
  7290. }
  7291. if (this.sliding) {
  7292. for (var i = 0; i < numWheels; i++) {
  7293. var wheel = wheelInfos[i];
  7294. if (wheel.sideImpulse !== 0) {
  7295. if (wheel.skidInfo < 1){
  7296. wheel.forwardImpulse *= wheel.skidInfo;
  7297. wheel.sideImpulse *= wheel.skidInfo;
  7298. }
  7299. }
  7300. }
  7301. }
  7302. // apply the impulses
  7303. for (var i = 0; i < numWheels; i++) {
  7304. var wheel = wheelInfos[i];
  7305. var rel_pos = new Vec3();
  7306. wheel.raycastResult.hitPointWorld.vsub(chassisBody.position, rel_pos);
  7307. // cannons applyimpulse is using world coord for the position
  7308. //rel_pos.copy(wheel.raycastResult.hitPointWorld);
  7309. if (wheel.forwardImpulse !== 0) {
  7310. var impulse = new Vec3();
  7311. forwardWS[i].scale(wheel.forwardImpulse, impulse);
  7312. chassisBody.applyImpulse(impulse, rel_pos);
  7313. }
  7314. if (wheel.sideImpulse !== 0){
  7315. var groundObject = wheel.raycastResult.body;
  7316. var rel_pos2 = new Vec3();
  7317. wheel.raycastResult.hitPointWorld.vsub(groundObject.position, rel_pos2);
  7318. //rel_pos2.copy(wheel.raycastResult.hitPointWorld);
  7319. var sideImp = new Vec3();
  7320. axle[i].scale(wheel.sideImpulse, sideImp);
  7321. // Scale the relative position in the up direction with rollInfluence.
  7322. // If rollInfluence is 1, the impulse will be applied on the hitPoint (easy to roll over), if it is zero it will be applied in the same plane as the center of mass (not easy to roll over).
  7323. chassisBody.vectorToLocalFrame(rel_pos, rel_pos);
  7324. rel_pos['xyz'[this.indexUpAxis]] *= wheel.rollInfluence;
  7325. chassisBody.vectorToWorldFrame(rel_pos, rel_pos);
  7326. chassisBody.applyImpulse(sideImp, rel_pos);
  7327. //apply friction impulse on the ground
  7328. sideImp.scale(-1, sideImp);
  7329. groundObject.applyImpulse(sideImp, rel_pos2);
  7330. }
  7331. }
  7332. };
  7333. var calcRollingFriction_vel1 = new Vec3();
  7334. var calcRollingFriction_vel2 = new Vec3();
  7335. var calcRollingFriction_vel = new Vec3();
  7336. function calcRollingFriction(body0, body1, frictionPosWorld, frictionDirectionWorld, maxImpulse) {
  7337. var j1 = 0;
  7338. var contactPosWorld = frictionPosWorld;
  7339. // var rel_pos1 = new Vec3();
  7340. // var rel_pos2 = new Vec3();
  7341. var vel1 = calcRollingFriction_vel1;
  7342. var vel2 = calcRollingFriction_vel2;
  7343. var vel = calcRollingFriction_vel;
  7344. // contactPosWorld.vsub(body0.position, rel_pos1);
  7345. // contactPosWorld.vsub(body1.position, rel_pos2);
  7346. body0.getVelocityAtWorldPoint(contactPosWorld, vel1);
  7347. body1.getVelocityAtWorldPoint(contactPosWorld, vel2);
  7348. vel1.vsub(vel2, vel);
  7349. var vrel = frictionDirectionWorld.dot(vel);
  7350. var denom0 = computeImpulseDenominator(body0, frictionPosWorld, frictionDirectionWorld);
  7351. var denom1 = computeImpulseDenominator(body1, frictionPosWorld, frictionDirectionWorld);
  7352. var relaxation = 1;
  7353. var jacDiagABInv = relaxation / (denom0 + denom1);
  7354. // calculate j that moves us to zero relative velocity
  7355. j1 = -vrel * jacDiagABInv;
  7356. if (maxImpulse < j1) {
  7357. j1 = maxImpulse;
  7358. }
  7359. if (j1 < -maxImpulse) {
  7360. j1 = -maxImpulse;
  7361. }
  7362. return j1;
  7363. }
  7364. var computeImpulseDenominator_r0 = new Vec3();
  7365. var computeImpulseDenominator_c0 = new Vec3();
  7366. var computeImpulseDenominator_vec = new Vec3();
  7367. var computeImpulseDenominator_m = new Vec3();
  7368. function computeImpulseDenominator(body, pos, normal) {
  7369. var r0 = computeImpulseDenominator_r0;
  7370. var c0 = computeImpulseDenominator_c0;
  7371. var vec = computeImpulseDenominator_vec;
  7372. var m = computeImpulseDenominator_m;
  7373. pos.vsub(body.position, r0);
  7374. r0.cross(normal, c0);
  7375. body.invInertiaWorld.vmult(c0, m);
  7376. m.cross(r0, vec);
  7377. return body.invMass + normal.dot(vec);
  7378. }
  7379. var resolveSingleBilateral_vel1 = new Vec3();
  7380. var resolveSingleBilateral_vel2 = new Vec3();
  7381. var resolveSingleBilateral_vel = new Vec3();
  7382. //bilateral constraint between two dynamic objects
  7383. function resolveSingleBilateral(body1, pos1, body2, pos2, normal, impulse){
  7384. var normalLenSqr = normal.norm2();
  7385. if (normalLenSqr > 1.1){
  7386. return 0; // no impulse
  7387. }
  7388. // var rel_pos1 = new Vec3();
  7389. // var rel_pos2 = new Vec3();
  7390. // pos1.vsub(body1.position, rel_pos1);
  7391. // pos2.vsub(body2.position, rel_pos2);
  7392. var vel1 = resolveSingleBilateral_vel1;
  7393. var vel2 = resolveSingleBilateral_vel2;
  7394. var vel = resolveSingleBilateral_vel;
  7395. body1.getVelocityAtWorldPoint(pos1, vel1);
  7396. body2.getVelocityAtWorldPoint(pos2, vel2);
  7397. vel1.vsub(vel2, vel);
  7398. var rel_vel = normal.dot(vel);
  7399. var contactDamping = 0.2;
  7400. var massTerm = 1 / (body1.invMass + body2.invMass);
  7401. var impulse = - contactDamping * rel_vel * massTerm;
  7402. return impulse;
  7403. }
  7404. },{"../collision/Ray":25,"../collision/RaycastResult":26,"../math/Quaternion":44,"../math/Vec3":46,"../objects/WheelInfo":52,"./Body":47}],49:[function(require,module,exports){
  7405. var Body = require('./Body');
  7406. var Sphere = require('../shapes/Sphere');
  7407. var Box = require('../shapes/Box');
  7408. var Vec3 = require('../math/Vec3');
  7409. var HingeConstraint = require('../constraints/HingeConstraint');
  7410. module.exports = RigidVehicle;
  7411. /**
  7412. * Simple vehicle helper class with spherical rigid body wheels.
  7413. * @class RigidVehicle
  7414. * @constructor
  7415. * @param {Body} [options.chassisBody]
  7416. */
  7417. function RigidVehicle(options){
  7418. this.wheelBodies = [];
  7419. /**
  7420. * @property coordinateSystem
  7421. * @type {Vec3}
  7422. */
  7423. this.coordinateSystem = typeof(options.coordinateSystem)==='undefined' ? new Vec3(1, 2, 3) : options.coordinateSystem.clone();
  7424. /**
  7425. * @property {Body} chassisBody
  7426. */
  7427. this.chassisBody = options.chassisBody;
  7428. if(!this.chassisBody){
  7429. // No chassis body given. Create it!
  7430. var chassisShape = new Box(new Vec3(5, 2, 0.5));
  7431. this.chassisBody = new Body(1, chassisShape);
  7432. }
  7433. /**
  7434. * @property constraints
  7435. * @type {Array}
  7436. */
  7437. this.constraints = [];
  7438. this.wheelAxes = [];
  7439. this.wheelForces = [];
  7440. }
  7441. /**
  7442. * Add a wheel
  7443. * @method addWheel
  7444. * @param {object} options
  7445. * @param {boolean} [options.isFrontWheel]
  7446. * @param {Vec3} [options.position] Position of the wheel, locally in the chassis body.
  7447. * @param {Vec3} [options.direction] Slide direction of the wheel along the suspension.
  7448. * @param {Vec3} [options.axis] Axis of rotation of the wheel, locally defined in the chassis.
  7449. * @param {Body} [options.body] The wheel body.
  7450. */
  7451. RigidVehicle.prototype.addWheel = function(options){
  7452. options = options || {};
  7453. var wheelBody = options.body;
  7454. if(!wheelBody){
  7455. wheelBody = new Body(1, new Sphere(1.2));
  7456. }
  7457. this.wheelBodies.push(wheelBody);
  7458. this.wheelForces.push(0);
  7459. // Position constrain wheels
  7460. var zero = new Vec3();
  7461. var position = typeof(options.position) !== 'undefined' ? options.position.clone() : new Vec3();
  7462. // Set position locally to the chassis
  7463. var worldPosition = new Vec3();
  7464. this.chassisBody.pointToWorldFrame(position, worldPosition);
  7465. wheelBody.position.set(worldPosition.x, worldPosition.y, worldPosition.z);
  7466. // Constrain wheel
  7467. var axis = typeof(options.axis) !== 'undefined' ? options.axis.clone() : new Vec3(0, 1, 0);
  7468. this.wheelAxes.push(axis);
  7469. var hingeConstraint = new HingeConstraint(this.chassisBody, wheelBody, {
  7470. pivotA: position,
  7471. axisA: axis,
  7472. pivotB: Vec3.ZERO,
  7473. axisB: axis,
  7474. collideConnected: false
  7475. });
  7476. this.constraints.push(hingeConstraint);
  7477. return this.wheelBodies.length - 1;
  7478. };
  7479. /**
  7480. * Set the steering value of a wheel.
  7481. * @method setSteeringValue
  7482. * @param {number} value
  7483. * @param {integer} wheelIndex
  7484. * @todo check coordinateSystem
  7485. */
  7486. RigidVehicle.prototype.setSteeringValue = function(value, wheelIndex){
  7487. // Set angle of the hinge axis
  7488. var axis = this.wheelAxes[wheelIndex];
  7489. var c = Math.cos(value),
  7490. s = Math.sin(value),
  7491. x = axis.x,
  7492. y = axis.y;
  7493. this.constraints[wheelIndex].axisA.set(
  7494. c*x -s*y,
  7495. s*x +c*y,
  7496. 0
  7497. );
  7498. };
  7499. /**
  7500. * Set the target rotational speed of the hinge constraint.
  7501. * @method setMotorSpeed
  7502. * @param {number} value
  7503. * @param {integer} wheelIndex
  7504. */
  7505. RigidVehicle.prototype.setMotorSpeed = function(value, wheelIndex){
  7506. var hingeConstraint = this.constraints[wheelIndex];
  7507. hingeConstraint.enableMotor();
  7508. hingeConstraint.motorTargetVelocity = value;
  7509. };
  7510. /**
  7511. * Set the target rotational speed of the hinge constraint.
  7512. * @method disableMotor
  7513. * @param {number} value
  7514. * @param {integer} wheelIndex
  7515. */
  7516. RigidVehicle.prototype.disableMotor = function(wheelIndex){
  7517. var hingeConstraint = this.constraints[wheelIndex];
  7518. hingeConstraint.disableMotor();
  7519. };
  7520. var torque = new Vec3();
  7521. /**
  7522. * Set the wheel force to apply on one of the wheels each time step
  7523. * @method setWheelForce
  7524. * @param {number} value
  7525. * @param {integer} wheelIndex
  7526. */
  7527. RigidVehicle.prototype.setWheelForce = function(value, wheelIndex){
  7528. this.wheelForces[wheelIndex] = value;
  7529. };
  7530. /**
  7531. * Apply a torque on one of the wheels.
  7532. * @method applyWheelForce
  7533. * @param {number} value
  7534. * @param {integer} wheelIndex
  7535. */
  7536. RigidVehicle.prototype.applyWheelForce = function(value, wheelIndex){
  7537. var axis = this.wheelAxes[wheelIndex];
  7538. var wheelBody = this.wheelBodies[wheelIndex];
  7539. var bodyTorque = wheelBody.torque;
  7540. axis.scale(value, torque);
  7541. wheelBody.vectorToWorldFrame(torque, torque);
  7542. bodyTorque.vadd(torque, bodyTorque);
  7543. };
  7544. /**
  7545. * Add the vehicle including its constraints to the world.
  7546. * @method addToWorld
  7547. * @param {World} world
  7548. */
  7549. RigidVehicle.prototype.addToWorld = function(world){
  7550. var constraints = this.constraints;
  7551. var bodies = this.wheelBodies.concat([this.chassisBody]);
  7552. for (var i = 0; i < bodies.length; i++) {
  7553. world.addBody(bodies[i]);
  7554. }
  7555. for (var i = 0; i < constraints.length; i++) {
  7556. world.addConstraint(constraints[i]);
  7557. }
  7558. world.addEventListener('preStep', this._update.bind(this));
  7559. };
  7560. RigidVehicle.prototype._update = function(){
  7561. var wheelForces = this.wheelForces;
  7562. for (var i = 0; i < wheelForces.length; i++) {
  7563. this.applyWheelForce(wheelForces[i], i);
  7564. }
  7565. };
  7566. /**
  7567. * Remove the vehicle including its constraints from the world.
  7568. * @method removeFromWorld
  7569. * @param {World} world
  7570. */
  7571. RigidVehicle.prototype.removeFromWorld = function(world){
  7572. var constraints = this.constraints;
  7573. var bodies = this.wheelBodies.concat([this.chassisBody]);
  7574. for (var i = 0; i < bodies.length; i++) {
  7575. world.remove(bodies[i]);
  7576. }
  7577. for (var i = 0; i < constraints.length; i++) {
  7578. world.removeConstraint(constraints[i]);
  7579. }
  7580. };
  7581. var worldAxis = new Vec3();
  7582. /**
  7583. * Get current rotational velocity of a wheel
  7584. * @method getWheelSpeed
  7585. * @param {integer} wheelIndex
  7586. */
  7587. RigidVehicle.prototype.getWheelSpeed = function(wheelIndex){
  7588. var axis = this.wheelAxes[wheelIndex];
  7589. var wheelBody = this.wheelBodies[wheelIndex];
  7590. var w = wheelBody.angularVelocity;
  7591. this.chassisBody.vectorToWorldFrame(axis, worldAxis);
  7592. return w.dot(worldAxis);
  7593. };
  7594. },{"../constraints/HingeConstraint":31,"../math/Vec3":46,"../shapes/Box":53,"../shapes/Sphere":60,"./Body":47}],50:[function(require,module,exports){
  7595. module.exports = SPHSystem;
  7596. var Shape = require('../shapes/Shape');
  7597. var Vec3 = require('../math/Vec3');
  7598. var Quaternion = require('../math/Quaternion');
  7599. var Particle = require('../shapes/Particle');
  7600. var Body = require('../objects/Body');
  7601. var Material = require('../material/Material');
  7602. /**
  7603. * Smoothed-particle hydrodynamics system
  7604. * @class SPHSystem
  7605. * @constructor
  7606. */
  7607. function SPHSystem(){
  7608. this.particles = [];
  7609. /**
  7610. * Density of the system (kg/m3).
  7611. * @property {number} density
  7612. */
  7613. this.density = 1;
  7614. /**
  7615. * Distance below which two particles are considered to be neighbors.
  7616. * It should be adjusted so there are about 15-20 neighbor particles within this radius.
  7617. * @property {number} smoothingRadius
  7618. */
  7619. this.smoothingRadius = 1;
  7620. this.speedOfSound = 1;
  7621. /**
  7622. * Viscosity of the system.
  7623. * @property {number} viscosity
  7624. */
  7625. this.viscosity = 0.01;
  7626. this.eps = 0.000001;
  7627. // Stuff Computed per particle
  7628. this.pressures = [];
  7629. this.densities = [];
  7630. this.neighbors = [];
  7631. }
  7632. /**
  7633. * Add a particle to the system.
  7634. * @method add
  7635. * @param {Body} particle
  7636. */
  7637. SPHSystem.prototype.add = function(particle){
  7638. this.particles.push(particle);
  7639. if(this.neighbors.length < this.particles.length){
  7640. this.neighbors.push([]);
  7641. }
  7642. };
  7643. /**
  7644. * Remove a particle from the system.
  7645. * @method remove
  7646. * @param {Body} particle
  7647. */
  7648. SPHSystem.prototype.remove = function(particle){
  7649. var idx = this.particles.indexOf(particle);
  7650. if(idx !== -1){
  7651. this.particles.splice(idx,1);
  7652. if(this.neighbors.length > this.particles.length){
  7653. this.neighbors.pop();
  7654. }
  7655. }
  7656. };
  7657. /**
  7658. * Get neighbors within smoothing volume, save in the array neighbors
  7659. * @method getNeighbors
  7660. * @param {Body} particle
  7661. * @param {Array} neighbors
  7662. */
  7663. var SPHSystem_getNeighbors_dist = new Vec3();
  7664. SPHSystem.prototype.getNeighbors = function(particle,neighbors){
  7665. var N = this.particles.length,
  7666. id = particle.id,
  7667. R2 = this.smoothingRadius * this.smoothingRadius,
  7668. dist = SPHSystem_getNeighbors_dist;
  7669. for(var i=0; i!==N; i++){
  7670. var p = this.particles[i];
  7671. p.position.vsub(particle.position,dist);
  7672. if(id!==p.id && dist.norm2() < R2){
  7673. neighbors.push(p);
  7674. }
  7675. }
  7676. };
  7677. // Temp vectors for calculation
  7678. var SPHSystem_update_dist = new Vec3(),
  7679. SPHSystem_update_a_pressure = new Vec3(),
  7680. SPHSystem_update_a_visc = new Vec3(),
  7681. SPHSystem_update_gradW = new Vec3(),
  7682. SPHSystem_update_r_vec = new Vec3(),
  7683. SPHSystem_update_u = new Vec3(); // Relative velocity
  7684. SPHSystem.prototype.update = function(){
  7685. var N = this.particles.length,
  7686. dist = SPHSystem_update_dist,
  7687. cs = this.speedOfSound,
  7688. eps = this.eps;
  7689. for(var i=0; i!==N; i++){
  7690. var p = this.particles[i]; // Current particle
  7691. var neighbors = this.neighbors[i];
  7692. // Get neighbors
  7693. neighbors.length = 0;
  7694. this.getNeighbors(p,neighbors);
  7695. neighbors.push(this.particles[i]); // Add current too
  7696. var numNeighbors = neighbors.length;
  7697. // Accumulate density for the particle
  7698. var sum = 0.0;
  7699. for(var j=0; j!==numNeighbors; j++){
  7700. //printf("Current particle has position %f %f %f\n",objects[id].pos.x(),objects[id].pos.y(),objects[id].pos.z());
  7701. p.position.vsub(neighbors[j].position, dist);
  7702. var len = dist.norm();
  7703. var weight = this.w(len);
  7704. sum += neighbors[j].mass * weight;
  7705. }
  7706. // Save
  7707. this.densities[i] = sum;
  7708. this.pressures[i] = cs * cs * (this.densities[i] - this.density);
  7709. }
  7710. // Add forces
  7711. // Sum to these accelerations
  7712. var a_pressure= SPHSystem_update_a_pressure;
  7713. var a_visc = SPHSystem_update_a_visc;
  7714. var gradW = SPHSystem_update_gradW;
  7715. var r_vec = SPHSystem_update_r_vec;
  7716. var u = SPHSystem_update_u;
  7717. for(var i=0; i!==N; i++){
  7718. var particle = this.particles[i];
  7719. a_pressure.set(0,0,0);
  7720. a_visc.set(0,0,0);
  7721. // Init vars
  7722. var Pij;
  7723. var nabla;
  7724. var Vij;
  7725. // Sum up for all other neighbors
  7726. var neighbors = this.neighbors[i];
  7727. var numNeighbors = neighbors.length;
  7728. //printf("Neighbors: ");
  7729. for(var j=0; j!==numNeighbors; j++){
  7730. var neighbor = neighbors[j];
  7731. //printf("%d ",nj);
  7732. // Get r once for all..
  7733. particle.position.vsub(neighbor.position,r_vec);
  7734. var r = r_vec.norm();
  7735. // Pressure contribution
  7736. Pij = -neighbor.mass * (this.pressures[i] / (this.densities[i]*this.densities[i] + eps) + this.pressures[j] / (this.densities[j]*this.densities[j] + eps));
  7737. this.gradw(r_vec, gradW);
  7738. // Add to pressure acceleration
  7739. gradW.mult(Pij , gradW);
  7740. a_pressure.vadd(gradW, a_pressure);
  7741. // Viscosity contribution
  7742. neighbor.velocity.vsub(particle.velocity, u);
  7743. u.mult( 1.0 / (0.0001+this.densities[i] * this.densities[j]) * this.viscosity * neighbor.mass , u );
  7744. nabla = this.nablaw(r);
  7745. u.mult(nabla,u);
  7746. // Add to viscosity acceleration
  7747. a_visc.vadd( u, a_visc );
  7748. }
  7749. // Calculate force
  7750. a_visc.mult(particle.mass, a_visc);
  7751. a_pressure.mult(particle.mass, a_pressure);
  7752. // Add force to particles
  7753. particle.force.vadd(a_visc, particle.force);
  7754. particle.force.vadd(a_pressure, particle.force);
  7755. }
  7756. };
  7757. // Calculate the weight using the W(r) weightfunction
  7758. SPHSystem.prototype.w = function(r){
  7759. // 315
  7760. var h = this.smoothingRadius;
  7761. return 315.0/(64.0*Math.PI*Math.pow(h,9)) * Math.pow(h*h-r*r,3);
  7762. };
  7763. // calculate gradient of the weight function
  7764. SPHSystem.prototype.gradw = function(rVec,resultVec){
  7765. var r = rVec.norm(),
  7766. h = this.smoothingRadius;
  7767. rVec.mult(945.0/(32.0*Math.PI*Math.pow(h,9)) * Math.pow((h*h-r*r),2) , resultVec);
  7768. };
  7769. // Calculate nabla(W)
  7770. SPHSystem.prototype.nablaw = function(r){
  7771. var h = this.smoothingRadius;
  7772. var nabla = 945.0/(32.0*Math.PI*Math.pow(h,9)) * (h*h-r*r)*(7*r*r - 3*h*h);
  7773. return nabla;
  7774. };
  7775. },{"../material/Material":41,"../math/Quaternion":44,"../math/Vec3":46,"../objects/Body":47,"../shapes/Particle":57,"../shapes/Shape":59}],51:[function(require,module,exports){
  7776. var Vec3 = require('../math/Vec3');
  7777. module.exports = Spring;
  7778. /**
  7779. * A spring, connecting two bodies.
  7780. *
  7781. * @class Spring
  7782. * @constructor
  7783. * @param {Body} bodyA
  7784. * @param {Body} bodyB
  7785. * @param {Object} [options]
  7786. * @param {number} [options.restLength] A number > 0. Default: 1
  7787. * @param {number} [options.stiffness] A number >= 0. Default: 100
  7788. * @param {number} [options.damping] A number >= 0. Default: 1
  7789. * @param {Vec3} [options.worldAnchorA] Where to hook the spring to body A, in world coordinates.
  7790. * @param {Vec3} [options.worldAnchorB]
  7791. * @param {Vec3} [options.localAnchorA] Where to hook the spring to body A, in local body coordinates.
  7792. * @param {Vec3} [options.localAnchorB]
  7793. */
  7794. function Spring(bodyA,bodyB,options){
  7795. options = options || {};
  7796. /**
  7797. * Rest length of the spring.
  7798. * @property restLength
  7799. * @type {number}
  7800. */
  7801. this.restLength = typeof(options.restLength) === "number" ? options.restLength : 1;
  7802. /**
  7803. * Stiffness of the spring.
  7804. * @property stiffness
  7805. * @type {number}
  7806. */
  7807. this.stiffness = options.stiffness || 100;
  7808. /**
  7809. * Damping of the spring.
  7810. * @property damping
  7811. * @type {number}
  7812. */
  7813. this.damping = options.damping || 1;
  7814. /**
  7815. * First connected body.
  7816. * @property bodyA
  7817. * @type {Body}
  7818. */
  7819. this.bodyA = bodyA;
  7820. /**
  7821. * Second connected body.
  7822. * @property bodyB
  7823. * @type {Body}
  7824. */
  7825. this.bodyB = bodyB;
  7826. /**
  7827. * Anchor for bodyA in local bodyA coordinates.
  7828. * @property localAnchorA
  7829. * @type {Vec3}
  7830. */
  7831. this.localAnchorA = new Vec3();
  7832. /**
  7833. * Anchor for bodyB in local bodyB coordinates.
  7834. * @property localAnchorB
  7835. * @type {Vec3}
  7836. */
  7837. this.localAnchorB = new Vec3();
  7838. if(options.localAnchorA){
  7839. this.localAnchorA.copy(options.localAnchorA);
  7840. }
  7841. if(options.localAnchorB){
  7842. this.localAnchorB.copy(options.localAnchorB);
  7843. }
  7844. if(options.worldAnchorA){
  7845. this.setWorldAnchorA(options.worldAnchorA);
  7846. }
  7847. if(options.worldAnchorB){
  7848. this.setWorldAnchorB(options.worldAnchorB);
  7849. }
  7850. }
  7851. /**
  7852. * Set the anchor point on body A, using world coordinates.
  7853. * @method setWorldAnchorA
  7854. * @param {Vec3} worldAnchorA
  7855. */
  7856. Spring.prototype.setWorldAnchorA = function(worldAnchorA){
  7857. this.bodyA.pointToLocalFrame(worldAnchorA,this.localAnchorA);
  7858. };
  7859. /**
  7860. * Set the anchor point on body B, using world coordinates.
  7861. * @method setWorldAnchorB
  7862. * @param {Vec3} worldAnchorB
  7863. */
  7864. Spring.prototype.setWorldAnchorB = function(worldAnchorB){
  7865. this.bodyB.pointToLocalFrame(worldAnchorB,this.localAnchorB);
  7866. };
  7867. /**
  7868. * Get the anchor point on body A, in world coordinates.
  7869. * @method getWorldAnchorA
  7870. * @param {Vec3} result The vector to store the result in.
  7871. */
  7872. Spring.prototype.getWorldAnchorA = function(result){
  7873. this.bodyA.pointToWorldFrame(this.localAnchorA,result);
  7874. };
  7875. /**
  7876. * Get the anchor point on body B, in world coordinates.
  7877. * @method getWorldAnchorB
  7878. * @param {Vec3} result The vector to store the result in.
  7879. */
  7880. Spring.prototype.getWorldAnchorB = function(result){
  7881. this.bodyB.pointToWorldFrame(this.localAnchorB,result);
  7882. };
  7883. var applyForce_r = new Vec3(),
  7884. applyForce_r_unit = new Vec3(),
  7885. applyForce_u = new Vec3(),
  7886. applyForce_f = new Vec3(),
  7887. applyForce_worldAnchorA = new Vec3(),
  7888. applyForce_worldAnchorB = new Vec3(),
  7889. applyForce_ri = new Vec3(),
  7890. applyForce_rj = new Vec3(),
  7891. applyForce_ri_x_f = new Vec3(),
  7892. applyForce_rj_x_f = new Vec3(),
  7893. applyForce_tmp = new Vec3();
  7894. /**
  7895. * Apply the spring force to the connected bodies.
  7896. * @method applyForce
  7897. */
  7898. Spring.prototype.applyForce = function(){
  7899. var k = this.stiffness,
  7900. d = this.damping,
  7901. l = this.restLength,
  7902. bodyA = this.bodyA,
  7903. bodyB = this.bodyB,
  7904. r = applyForce_r,
  7905. r_unit = applyForce_r_unit,
  7906. u = applyForce_u,
  7907. f = applyForce_f,
  7908. tmp = applyForce_tmp;
  7909. var worldAnchorA = applyForce_worldAnchorA,
  7910. worldAnchorB = applyForce_worldAnchorB,
  7911. ri = applyForce_ri,
  7912. rj = applyForce_rj,
  7913. ri_x_f = applyForce_ri_x_f,
  7914. rj_x_f = applyForce_rj_x_f;
  7915. // Get world anchors
  7916. this.getWorldAnchorA(worldAnchorA);
  7917. this.getWorldAnchorB(worldAnchorB);
  7918. // Get offset points
  7919. worldAnchorA.vsub(bodyA.position,ri);
  7920. worldAnchorB.vsub(bodyB.position,rj);
  7921. // Compute distance vector between world anchor points
  7922. worldAnchorB.vsub(worldAnchorA,r);
  7923. var rlen = r.norm();
  7924. r_unit.copy(r);
  7925. r_unit.normalize();
  7926. // Compute relative velocity of the anchor points, u
  7927. bodyB.velocity.vsub(bodyA.velocity,u);
  7928. // Add rotational velocity
  7929. bodyB.angularVelocity.cross(rj,tmp);
  7930. u.vadd(tmp,u);
  7931. bodyA.angularVelocity.cross(ri,tmp);
  7932. u.vsub(tmp,u);
  7933. // F = - k * ( x - L ) - D * ( u )
  7934. r_unit.mult(-k*(rlen-l) - d*u.dot(r_unit), f);
  7935. // Add forces to bodies
  7936. bodyA.force.vsub(f,bodyA.force);
  7937. bodyB.force.vadd(f,bodyB.force);
  7938. // Angular force
  7939. ri.cross(f,ri_x_f);
  7940. rj.cross(f,rj_x_f);
  7941. bodyA.torque.vsub(ri_x_f,bodyA.torque);
  7942. bodyB.torque.vadd(rj_x_f,bodyB.torque);
  7943. };
  7944. },{"../math/Vec3":46}],52:[function(require,module,exports){
  7945. var Vec3 = require('../math/Vec3');
  7946. var Transform = require('../math/Transform');
  7947. var RaycastResult = require('../collision/RaycastResult');
  7948. var Utils = require('../utils/Utils');
  7949. module.exports = WheelInfo;
  7950. /**
  7951. * @class WheelInfo
  7952. * @constructor
  7953. * @param {Object} [options]
  7954. *
  7955. * @param {Vec3} [options.chassisConnectionPointLocal]
  7956. * @param {Vec3} [options.chassisConnectionPointWorld]
  7957. * @param {Vec3} [options.directionLocal]
  7958. * @param {Vec3} [options.directionWorld]
  7959. * @param {Vec3} [options.axleLocal]
  7960. * @param {Vec3} [options.axleWorld]
  7961. * @param {number} [options.suspensionRestLength=1]
  7962. * @param {number} [options.suspensionMaxLength=2]
  7963. * @param {number} [options.radius=1]
  7964. * @param {number} [options.suspensionStiffness=100]
  7965. * @param {number} [options.dampingCompression=10]
  7966. * @param {number} [options.dampingRelaxation=10]
  7967. * @param {number} [options.frictionSlip=10000]
  7968. * @param {number} [options.steering=0]
  7969. * @param {number} [options.rotation=0]
  7970. * @param {number} [options.deltaRotation=0]
  7971. * @param {number} [options.rollInfluence=0.01]
  7972. * @param {number} [options.maxSuspensionForce]
  7973. * @param {boolean} [options.isFrontWheel=true]
  7974. * @param {number} [options.clippedInvContactDotSuspension=1]
  7975. * @param {number} [options.suspensionRelativeVelocity=0]
  7976. * @param {number} [options.suspensionForce=0]
  7977. * @param {number} [options.skidInfo=0]
  7978. * @param {number} [options.suspensionLength=0]
  7979. * @param {number} [options.maxSuspensionTravel=1]
  7980. * @param {boolean} [options.useCustomSlidingRotationalSpeed=false]
  7981. * @param {number} [options.customSlidingRotationalSpeed=-0.1]
  7982. */
  7983. function WheelInfo(options){
  7984. options = Utils.defaults(options, {
  7985. chassisConnectionPointLocal: new Vec3(),
  7986. chassisConnectionPointWorld: new Vec3(),
  7987. directionLocal: new Vec3(),
  7988. directionWorld: new Vec3(),
  7989. axleLocal: new Vec3(),
  7990. axleWorld: new Vec3(),
  7991. suspensionRestLength: 1,
  7992. suspensionMaxLength: 2,
  7993. radius: 1,
  7994. suspensionStiffness: 100,
  7995. dampingCompression: 10,
  7996. dampingRelaxation: 10,
  7997. frictionSlip: 10000,
  7998. steering: 0,
  7999. rotation: 0,
  8000. deltaRotation: 0,
  8001. rollInfluence: 0.01,
  8002. maxSuspensionForce: Number.MAX_VALUE,
  8003. isFrontWheel: true,
  8004. clippedInvContactDotSuspension: 1,
  8005. suspensionRelativeVelocity: 0,
  8006. suspensionForce: 0,
  8007. skidInfo: 0,
  8008. suspensionLength: 0,
  8009. maxSuspensionTravel: 1,
  8010. useCustomSlidingRotationalSpeed: false,
  8011. customSlidingRotationalSpeed: -0.1
  8012. });
  8013. /**
  8014. * Max travel distance of the suspension, in meters.
  8015. * @property {number} maxSuspensionTravel
  8016. */
  8017. this.maxSuspensionTravel = options.maxSuspensionTravel;
  8018. /**
  8019. * Speed to apply to the wheel rotation when the wheel is sliding.
  8020. * @property {number} customSlidingRotationalSpeed
  8021. */
  8022. this.customSlidingRotationalSpeed = options.customSlidingRotationalSpeed;
  8023. /**
  8024. * If the customSlidingRotationalSpeed should be used.
  8025. * @property {Boolean} useCustomSlidingRotationalSpeed
  8026. */
  8027. this.useCustomSlidingRotationalSpeed = options.useCustomSlidingRotationalSpeed;
  8028. /**
  8029. * @property {Boolean} sliding
  8030. */
  8031. this.sliding = false;
  8032. /**
  8033. * Connection point, defined locally in the chassis body frame.
  8034. * @property {Vec3} chassisConnectionPointLocal
  8035. */
  8036. this.chassisConnectionPointLocal = options.chassisConnectionPointLocal.clone();
  8037. /**
  8038. * @property {Vec3} chassisConnectionPointWorld
  8039. */
  8040. this.chassisConnectionPointWorld = options.chassisConnectionPointWorld.clone();
  8041. /**
  8042. * @property {Vec3} directionLocal
  8043. */
  8044. this.directionLocal = options.directionLocal.clone();
  8045. /**
  8046. * @property {Vec3} directionWorld
  8047. */
  8048. this.directionWorld = options.directionWorld.clone();
  8049. /**
  8050. * @property {Vec3} axleLocal
  8051. */
  8052. this.axleLocal = options.axleLocal.clone();
  8053. /**
  8054. * @property {Vec3} axleWorld
  8055. */
  8056. this.axleWorld = options.axleWorld.clone();
  8057. /**
  8058. * @property {number} suspensionRestLength
  8059. */
  8060. this.suspensionRestLength = options.suspensionRestLength;
  8061. /**
  8062. * @property {number} suspensionMaxLength
  8063. */
  8064. this.suspensionMaxLength = options.suspensionMaxLength;
  8065. /**
  8066. * @property {number} radius
  8067. */
  8068. this.radius = options.radius;
  8069. /**
  8070. * @property {number} suspensionStiffness
  8071. */
  8072. this.suspensionStiffness = options.suspensionStiffness;
  8073. /**
  8074. * @property {number} dampingCompression
  8075. */
  8076. this.dampingCompression = options.dampingCompression;
  8077. /**
  8078. * @property {number} dampingRelaxation
  8079. */
  8080. this.dampingRelaxation = options.dampingRelaxation;
  8081. /**
  8082. * @property {number} frictionSlip
  8083. */
  8084. this.frictionSlip = options.frictionSlip;
  8085. /**
  8086. * @property {number} steering
  8087. */
  8088. this.steering = 0;
  8089. /**
  8090. * Rotation value, in radians.
  8091. * @property {number} rotation
  8092. */
  8093. this.rotation = 0;
  8094. /**
  8095. * @property {number} deltaRotation
  8096. */
  8097. this.deltaRotation = 0;
  8098. /**
  8099. * @property {number} rollInfluence
  8100. */
  8101. this.rollInfluence = options.rollInfluence;
  8102. /**
  8103. * @property {number} maxSuspensionForce
  8104. */
  8105. this.maxSuspensionForce = options.maxSuspensionForce;
  8106. /**
  8107. * @property {number} engineForce
  8108. */
  8109. this.engineForce = 0;
  8110. /**
  8111. * @property {number} brake
  8112. */
  8113. this.brake = 0;
  8114. /**
  8115. * @property {number} isFrontWheel
  8116. */
  8117. this.isFrontWheel = options.isFrontWheel;
  8118. /**
  8119. * @property {number} clippedInvContactDotSuspension
  8120. */
  8121. this.clippedInvContactDotSuspension = 1;
  8122. /**
  8123. * @property {number} suspensionRelativeVelocity
  8124. */
  8125. this.suspensionRelativeVelocity = 0;
  8126. /**
  8127. * @property {number} suspensionForce
  8128. */
  8129. this.suspensionForce = 0;
  8130. /**
  8131. * @property {number} skidInfo
  8132. */
  8133. this.skidInfo = 0;
  8134. /**
  8135. * @property {number} suspensionLength
  8136. */
  8137. this.suspensionLength = 0;
  8138. /**
  8139. * @property {number} sideImpulse
  8140. */
  8141. this.sideImpulse = 0;
  8142. /**
  8143. * @property {number} forwardImpulse
  8144. */
  8145. this.forwardImpulse = 0;
  8146. /**
  8147. * The result from raycasting
  8148. * @property {RaycastResult} raycastResult
  8149. */
  8150. this.raycastResult = new RaycastResult();
  8151. /**
  8152. * Wheel world transform
  8153. * @property {Transform} worldTransform
  8154. */
  8155. this.worldTransform = new Transform();
  8156. /**
  8157. * @property {boolean} isInContact
  8158. */
  8159. this.isInContact = false;
  8160. }
  8161. var chassis_velocity_at_contactPoint = new Vec3();
  8162. var relpos = new Vec3();
  8163. var chassis_velocity_at_contactPoint = new Vec3();
  8164. WheelInfo.prototype.updateWheel = function(chassis){
  8165. var raycastResult = this.raycastResult;
  8166. if (this.isInContact){
  8167. var project= raycastResult.hitNormalWorld.dot(raycastResult.directionWorld);
  8168. raycastResult.hitPointWorld.vsub(chassis.position, relpos);
  8169. chassis.getVelocityAtWorldPoint(relpos, chassis_velocity_at_contactPoint);
  8170. var projVel = raycastResult.hitNormalWorld.dot( chassis_velocity_at_contactPoint );
  8171. if (project >= -0.1) {
  8172. this.suspensionRelativeVelocity = 0.0;
  8173. this.clippedInvContactDotSuspension = 1.0 / 0.1;
  8174. } else {
  8175. var inv = -1 / project;
  8176. this.suspensionRelativeVelocity = projVel * inv;
  8177. this.clippedInvContactDotSuspension = inv;
  8178. }
  8179. } else {
  8180. // Not in contact : position wheel in a nice (rest length) position
  8181. raycastResult.suspensionLength = this.suspensionRestLength;
  8182. this.suspensionRelativeVelocity = 0.0;
  8183. raycastResult.directionWorld.scale(-1, raycastResult.hitNormalWorld);
  8184. this.clippedInvContactDotSuspension = 1.0;
  8185. }
  8186. };
  8187. },{"../collision/RaycastResult":26,"../math/Transform":45,"../math/Vec3":46,"../utils/Utils":69}],53:[function(require,module,exports){
  8188. module.exports = Box;
  8189. var Shape = require('./Shape');
  8190. var Vec3 = require('../math/Vec3');
  8191. var ConvexPolyhedron = require('./ConvexPolyhedron');
  8192. /**
  8193. * A 3d box shape.
  8194. * @class Box
  8195. * @constructor
  8196. * @param {Vec3} halfExtents
  8197. * @author schteppe
  8198. * @extends Shape
  8199. */
  8200. function Box(halfExtents){
  8201. Shape.call(this);
  8202. this.type = Shape.types.BOX;
  8203. /**
  8204. * @property halfExtents
  8205. * @type {Vec3}
  8206. */
  8207. this.halfExtents = halfExtents;
  8208. /**
  8209. * Used by the contact generator to make contacts with other convex polyhedra for example
  8210. * @property convexPolyhedronRepresentation
  8211. * @type {ConvexPolyhedron}
  8212. */
  8213. this.convexPolyhedronRepresentation = null;
  8214. this.updateConvexPolyhedronRepresentation();
  8215. this.updateBoundingSphereRadius();
  8216. }
  8217. Box.prototype = new Shape();
  8218. Box.prototype.constructor = Box;
  8219. /**
  8220. * Updates the local convex polyhedron representation used for some collisions.
  8221. * @method updateConvexPolyhedronRepresentation
  8222. */
  8223. Box.prototype.updateConvexPolyhedronRepresentation = function(){
  8224. var sx = this.halfExtents.x;
  8225. var sy = this.halfExtents.y;
  8226. var sz = this.halfExtents.z;
  8227. var V = Vec3;
  8228. var vertices = [
  8229. new V(-sx,-sy,-sz),
  8230. new V( sx,-sy,-sz),
  8231. new V( sx, sy,-sz),
  8232. new V(-sx, sy,-sz),
  8233. new V(-sx,-sy, sz),
  8234. new V( sx,-sy, sz),
  8235. new V( sx, sy, sz),
  8236. new V(-sx, sy, sz)
  8237. ];
  8238. var indices = [
  8239. [3,2,1,0], // -z
  8240. [4,5,6,7], // +z
  8241. [5,4,0,1], // -y
  8242. [2,3,7,6], // +y
  8243. [0,4,7,3], // -x
  8244. [1,2,6,5], // +x
  8245. ];
  8246. var axes = [
  8247. new V(0, 0, 1),
  8248. new V(0, 1, 0),
  8249. new V(1, 0, 0)
  8250. ];
  8251. var h = new ConvexPolyhedron(vertices, indices);
  8252. this.convexPolyhedronRepresentation = h;
  8253. h.material = this.material;
  8254. };
  8255. /**
  8256. * @method calculateLocalInertia
  8257. * @param {Number} mass
  8258. * @param {Vec3} target
  8259. * @return {Vec3}
  8260. */
  8261. Box.prototype.calculateLocalInertia = function(mass,target){
  8262. target = target || new Vec3();
  8263. Box.calculateInertia(this.halfExtents, mass, target);
  8264. return target;
  8265. };
  8266. Box.calculateInertia = function(halfExtents,mass,target){
  8267. var e = halfExtents;
  8268. target.x = 1.0 / 12.0 * mass * ( 2*e.y*2*e.y + 2*e.z*2*e.z );
  8269. target.y = 1.0 / 12.0 * mass * ( 2*e.x*2*e.x + 2*e.z*2*e.z );
  8270. target.z = 1.0 / 12.0 * mass * ( 2*e.y*2*e.y + 2*e.x*2*e.x );
  8271. };
  8272. /**
  8273. * Get the box 6 side normals
  8274. * @method getSideNormals
  8275. * @param {array} sixTargetVectors An array of 6 vectors, to store the resulting side normals in.
  8276. * @param {Quaternion} quat Orientation to apply to the normal vectors. If not provided, the vectors will be in respect to the local frame.
  8277. * @return {array}
  8278. */
  8279. Box.prototype.getSideNormals = function(sixTargetVectors,quat){
  8280. var sides = sixTargetVectors;
  8281. var ex = this.halfExtents;
  8282. sides[0].set( ex.x, 0, 0);
  8283. sides[1].set( 0, ex.y, 0);
  8284. sides[2].set( 0, 0, ex.z);
  8285. sides[3].set( -ex.x, 0, 0);
  8286. sides[4].set( 0, -ex.y, 0);
  8287. sides[5].set( 0, 0, -ex.z);
  8288. if(quat!==undefined){
  8289. for(var i=0; i!==sides.length; i++){
  8290. quat.vmult(sides[i],sides[i]);
  8291. }
  8292. }
  8293. return sides;
  8294. };
  8295. Box.prototype.volume = function(){
  8296. return 8.0 * this.halfExtents.x * this.halfExtents.y * this.halfExtents.z;
  8297. };
  8298. Box.prototype.updateBoundingSphereRadius = function(){
  8299. this.boundingSphereRadius = this.halfExtents.norm();
  8300. };
  8301. var worldCornerTempPos = new Vec3();
  8302. var worldCornerTempNeg = new Vec3();
  8303. Box.prototype.forEachWorldCorner = function(pos,quat,callback){
  8304. var e = this.halfExtents;
  8305. var corners = [[ e.x, e.y, e.z],
  8306. [ -e.x, e.y, e.z],
  8307. [ -e.x, -e.y, e.z],
  8308. [ -e.x, -e.y, -e.z],
  8309. [ e.x, -e.y, -e.z],
  8310. [ e.x, e.y, -e.z],
  8311. [ -e.x, e.y, -e.z],
  8312. [ e.x, -e.y, e.z]];
  8313. for(var i=0; i<corners.length; i++){
  8314. worldCornerTempPos.set(corners[i][0],corners[i][1],corners[i][2]);
  8315. quat.vmult(worldCornerTempPos,worldCornerTempPos);
  8316. pos.vadd(worldCornerTempPos,worldCornerTempPos);
  8317. callback(worldCornerTempPos.x,
  8318. worldCornerTempPos.y,
  8319. worldCornerTempPos.z);
  8320. }
  8321. };
  8322. var worldCornersTemp = [
  8323. new Vec3(),
  8324. new Vec3(),
  8325. new Vec3(),
  8326. new Vec3(),
  8327. new Vec3(),
  8328. new Vec3(),
  8329. new Vec3(),
  8330. new Vec3()
  8331. ];
  8332. Box.prototype.calculateWorldAABB = function(pos,quat,min,max){
  8333. var e = this.halfExtents;
  8334. worldCornersTemp[0].set(e.x, e.y, e.z);
  8335. worldCornersTemp[1].set(-e.x, e.y, e.z);
  8336. worldCornersTemp[2].set(-e.x, -e.y, e.z);
  8337. worldCornersTemp[3].set(-e.x, -e.y, -e.z);
  8338. worldCornersTemp[4].set(e.x, -e.y, -e.z);
  8339. worldCornersTemp[5].set(e.x, e.y, -e.z);
  8340. worldCornersTemp[6].set(-e.x, e.y, -e.z);
  8341. worldCornersTemp[7].set(e.x, -e.y, e.z);
  8342. var wc = worldCornersTemp[0];
  8343. quat.vmult(wc, wc);
  8344. pos.vadd(wc, wc);
  8345. max.copy(wc);
  8346. min.copy(wc);
  8347. for(var i=1; i<8; i++){
  8348. var wc = worldCornersTemp[i];
  8349. quat.vmult(wc, wc);
  8350. pos.vadd(wc, wc);
  8351. var x = wc.x;
  8352. var y = wc.y;
  8353. var z = wc.z;
  8354. if(x > max.x){
  8355. max.x = x;
  8356. }
  8357. if(y > max.y){
  8358. max.y = y;
  8359. }
  8360. if(z > max.z){
  8361. max.z = z;
  8362. }
  8363. if(x < min.x){
  8364. min.x = x;
  8365. }
  8366. if(y < min.y){
  8367. min.y = y;
  8368. }
  8369. if(z < min.z){
  8370. min.z = z;
  8371. }
  8372. }
  8373. // Get each axis max
  8374. // min.set(Infinity,Infinity,Infinity);
  8375. // max.set(-Infinity,-Infinity,-Infinity);
  8376. // this.forEachWorldCorner(pos,quat,function(x,y,z){
  8377. // if(x > max.x){
  8378. // max.x = x;
  8379. // }
  8380. // if(y > max.y){
  8381. // max.y = y;
  8382. // }
  8383. // if(z > max.z){
  8384. // max.z = z;
  8385. // }
  8386. // if(x < min.x){
  8387. // min.x = x;
  8388. // }
  8389. // if(y < min.y){
  8390. // min.y = y;
  8391. // }
  8392. // if(z < min.z){
  8393. // min.z = z;
  8394. // }
  8395. // });
  8396. };
  8397. },{"../math/Vec3":46,"./ConvexPolyhedron":54,"./Shape":59}],54:[function(require,module,exports){
  8398. module.exports = ConvexPolyhedron;
  8399. var Shape = require('./Shape');
  8400. var Vec3 = require('../math/Vec3');
  8401. var Quaternion = require('../math/Quaternion');
  8402. var Transform = require('../math/Transform');
  8403. /**
  8404. * A set of polygons describing a convex shape.
  8405. * @class ConvexPolyhedron
  8406. * @constructor
  8407. * @extends Shape
  8408. * @description The shape MUST be convex for the code to work properly. No polygons may be coplanar (contained
  8409. * in the same 3D plane), instead these should be merged into one polygon.
  8410. *
  8411. * @param {array} points An array of Vec3's
  8412. * @param {array} faces Array of integer arrays, describing which vertices that is included in each face.
  8413. *
  8414. * @author qiao / https://github.com/qiao (original author, see https://github.com/qiao/three.js/commit/85026f0c769e4000148a67d45a9e9b9c5108836f)
  8415. * @author schteppe / https://github.com/schteppe
  8416. * @see http://www.altdevblogaday.com/2011/05/13/contact-generation-between-3d-convex-meshes/
  8417. * @see http://bullet.googlecode.com/svn/trunk/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
  8418. *
  8419. * @todo Move the clipping functions to ContactGenerator?
  8420. * @todo Automatically merge coplanar polygons in constructor.
  8421. */
  8422. function ConvexPolyhedron(points, faces, uniqueAxes) {
  8423. var that = this;
  8424. Shape.call(this);
  8425. this.type = Shape.types.CONVEXPOLYHEDRON;
  8426. /**
  8427. * Array of Vec3
  8428. * @property vertices
  8429. * @type {Array}
  8430. */
  8431. this.vertices = points||[];
  8432. this.worldVertices = []; // World transformed version of .vertices
  8433. this.worldVerticesNeedsUpdate = true;
  8434. /**
  8435. * Array of integer arrays, indicating which vertices each face consists of
  8436. * @property faces
  8437. * @type {Array}
  8438. */
  8439. this.faces = faces||[];
  8440. /**
  8441. * Array of Vec3
  8442. * @property faceNormals
  8443. * @type {Array}
  8444. */
  8445. this.faceNormals = [];
  8446. this.computeNormals();
  8447. this.worldFaceNormalsNeedsUpdate = true;
  8448. this.worldFaceNormals = []; // World transformed version of .faceNormals
  8449. /**
  8450. * Array of Vec3
  8451. * @property uniqueEdges
  8452. * @type {Array}
  8453. */
  8454. this.uniqueEdges = [];
  8455. /**
  8456. * If given, these locally defined, normalized axes are the only ones being checked when doing separating axis check.
  8457. * @property {Array} uniqueAxes
  8458. */
  8459. this.uniqueAxes = uniqueAxes ? uniqueAxes.slice() : null;
  8460. this.computeEdges();
  8461. this.updateBoundingSphereRadius();
  8462. }
  8463. ConvexPolyhedron.prototype = new Shape();
  8464. ConvexPolyhedron.prototype.constructor = ConvexPolyhedron;
  8465. var computeEdges_tmpEdge = new Vec3();
  8466. /**
  8467. * Computes uniqueEdges
  8468. * @method computeEdges
  8469. */
  8470. ConvexPolyhedron.prototype.computeEdges = function(){
  8471. var faces = this.faces;
  8472. var vertices = this.vertices;
  8473. var nv = vertices.length;
  8474. var edges = this.uniqueEdges;
  8475. edges.length = 0;
  8476. var edge = computeEdges_tmpEdge;
  8477. for(var i=0; i !== faces.length; i++){
  8478. var face = faces[i];
  8479. var numVertices = face.length;
  8480. for(var j = 0; j !== numVertices; j++){
  8481. var k = ( j+1 ) % numVertices;
  8482. vertices[face[j]].vsub(vertices[face[k]], edge);
  8483. edge.normalize();
  8484. var found = false;
  8485. for(var p=0; p !== edges.length; p++){
  8486. if (edges[p].almostEquals(edge) || edges[p].almostEquals(edge)){
  8487. found = true;
  8488. break;
  8489. }
  8490. }
  8491. if (!found){
  8492. edges.push(edge.clone());
  8493. }
  8494. }
  8495. }
  8496. };
  8497. /**
  8498. * Compute the normals of the faces. Will reuse existing Vec3 objects in the .faceNormals array if they exist.
  8499. * @method computeNormals
  8500. */
  8501. ConvexPolyhedron.prototype.computeNormals = function(){
  8502. this.faceNormals.length = this.faces.length;
  8503. // Generate normals
  8504. for(var i=0; i<this.faces.length; i++){
  8505. // Check so all vertices exists for this face
  8506. for(var j=0; j<this.faces[i].length; j++){
  8507. if(!this.vertices[this.faces[i][j]]){
  8508. throw new Error("Vertex "+this.faces[i][j]+" not found!");
  8509. }
  8510. }
  8511. var n = this.faceNormals[i] || new Vec3();
  8512. this.getFaceNormal(i,n);
  8513. n.negate(n);
  8514. this.faceNormals[i] = n;
  8515. var vertex = this.vertices[this.faces[i][0]];
  8516. if(n.dot(vertex) < 0){
  8517. 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.");
  8518. for(var j=0; j<this.faces[i].length; j++){
  8519. console.warn(".vertices["+this.faces[i][j]+"] = Vec3("+this.vertices[this.faces[i][j]].toString()+")");
  8520. }
  8521. }
  8522. }
  8523. };
  8524. /**
  8525. * Get face normal given 3 vertices
  8526. * @static
  8527. * @method getFaceNormal
  8528. * @param {Vec3} va
  8529. * @param {Vec3} vb
  8530. * @param {Vec3} vc
  8531. * @param {Vec3} target
  8532. */
  8533. var cb = new Vec3();
  8534. var ab = new Vec3();
  8535. ConvexPolyhedron.computeNormal = function ( va, vb, vc, target ) {
  8536. vb.vsub(va,ab);
  8537. vc.vsub(vb,cb);
  8538. cb.cross(ab,target);
  8539. if ( !target.isZero() ) {
  8540. target.normalize();
  8541. }
  8542. };
  8543. /**
  8544. * Compute the normal of a face from its vertices
  8545. * @method getFaceNormal
  8546. * @param {Number} i
  8547. * @param {Vec3} target
  8548. */
  8549. ConvexPolyhedron.prototype.getFaceNormal = function(i,target){
  8550. var f = this.faces[i];
  8551. var va = this.vertices[f[0]];
  8552. var vb = this.vertices[f[1]];
  8553. var vc = this.vertices[f[2]];
  8554. return ConvexPolyhedron.computeNormal(va,vb,vc,target);
  8555. };
  8556. /**
  8557. * @method clipAgainstHull
  8558. * @param {Vec3} posA
  8559. * @param {Quaternion} quatA
  8560. * @param {ConvexPolyhedron} hullB
  8561. * @param {Vec3} posB
  8562. * @param {Quaternion} quatB
  8563. * @param {Vec3} separatingNormal
  8564. * @param {Number} minDist Clamp distance
  8565. * @param {Number} maxDist
  8566. * @param {array} result The an array of contact point objects, see clipFaceAgainstHull
  8567. * @see http://bullet.googlecode.com/svn/trunk/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
  8568. */
  8569. var cah_WorldNormal = new Vec3();
  8570. ConvexPolyhedron.prototype.clipAgainstHull = function(posA,quatA,hullB,posB,quatB,separatingNormal,minDist,maxDist,result){
  8571. var WorldNormal = cah_WorldNormal;
  8572. var hullA = this;
  8573. var curMaxDist = maxDist;
  8574. var closestFaceB = -1;
  8575. var dmax = -Number.MAX_VALUE;
  8576. for(var face=0; face < hullB.faces.length; face++){
  8577. WorldNormal.copy(hullB.faceNormals[face]);
  8578. quatB.vmult(WorldNormal,WorldNormal);
  8579. //posB.vadd(WorldNormal,WorldNormal);
  8580. var d = WorldNormal.dot(separatingNormal);
  8581. if (d > dmax){
  8582. dmax = d;
  8583. closestFaceB = face;
  8584. }
  8585. }
  8586. var worldVertsB1 = [];
  8587. var polyB = hullB.faces[closestFaceB];
  8588. var numVertices = polyB.length;
  8589. for(var e0=0; e0<numVertices; e0++){
  8590. var b = hullB.vertices[polyB[e0]];
  8591. var worldb = new Vec3();
  8592. worldb.copy(b);
  8593. quatB.vmult(worldb,worldb);
  8594. posB.vadd(worldb,worldb);
  8595. worldVertsB1.push(worldb);
  8596. }
  8597. if (closestFaceB>=0){
  8598. this.clipFaceAgainstHull(separatingNormal,
  8599. posA,
  8600. quatA,
  8601. worldVertsB1,
  8602. minDist,
  8603. maxDist,
  8604. result);
  8605. }
  8606. };
  8607. /**
  8608. * Find the separating axis between this hull and another
  8609. * @method findSeparatingAxis
  8610. * @param {ConvexPolyhedron} hullB
  8611. * @param {Vec3} posA
  8612. * @param {Quaternion} quatA
  8613. * @param {Vec3} posB
  8614. * @param {Quaternion} quatB
  8615. * @param {Vec3} target The target vector to save the axis in
  8616. * @return {bool} Returns false if a separation is found, else true
  8617. */
  8618. var fsa_faceANormalWS3 = new Vec3(),
  8619. fsa_Worldnormal1 = new Vec3(),
  8620. fsa_deltaC = new Vec3(),
  8621. fsa_worldEdge0 = new Vec3(),
  8622. fsa_worldEdge1 = new Vec3(),
  8623. fsa_Cross = new Vec3();
  8624. ConvexPolyhedron.prototype.findSeparatingAxis = function(hullB,posA,quatA,posB,quatB,target, faceListA, faceListB){
  8625. var faceANormalWS3 = fsa_faceANormalWS3,
  8626. Worldnormal1 = fsa_Worldnormal1,
  8627. deltaC = fsa_deltaC,
  8628. worldEdge0 = fsa_worldEdge0,
  8629. worldEdge1 = fsa_worldEdge1,
  8630. Cross = fsa_Cross;
  8631. var dmin = Number.MAX_VALUE;
  8632. var hullA = this;
  8633. var curPlaneTests=0;
  8634. if(!hullA.uniqueAxes){
  8635. var numFacesA = faceListA ? faceListA.length : hullA.faces.length;
  8636. // Test face normals from hullA
  8637. for(var i=0; i<numFacesA; i++){
  8638. var fi = faceListA ? faceListA[i] : i;
  8639. // Get world face normal
  8640. faceANormalWS3.copy(hullA.faceNormals[fi]);
  8641. quatA.vmult(faceANormalWS3,faceANormalWS3);
  8642. var d = hullA.testSepAxis(faceANormalWS3, hullB, posA, quatA, posB, quatB);
  8643. if(d===false){
  8644. return false;
  8645. }
  8646. if(d<dmin){
  8647. dmin = d;
  8648. target.copy(faceANormalWS3);
  8649. }
  8650. }
  8651. } else {
  8652. // Test unique axes
  8653. for(var i = 0; i !== hullA.uniqueAxes.length; i++){
  8654. // Get world axis
  8655. quatA.vmult(hullA.uniqueAxes[i],faceANormalWS3);
  8656. var d = hullA.testSepAxis(faceANormalWS3, hullB, posA, quatA, posB, quatB);
  8657. if(d===false){
  8658. return false;
  8659. }
  8660. if(d<dmin){
  8661. dmin = d;
  8662. target.copy(faceANormalWS3);
  8663. }
  8664. }
  8665. }
  8666. if(!hullB.uniqueAxes){
  8667. // Test face normals from hullB
  8668. var numFacesB = faceListB ? faceListB.length : hullB.faces.length;
  8669. for(var i=0;i<numFacesB;i++){
  8670. var fi = faceListB ? faceListB[i] : i;
  8671. Worldnormal1.copy(hullB.faceNormals[fi]);
  8672. quatB.vmult(Worldnormal1,Worldnormal1);
  8673. curPlaneTests++;
  8674. var d = hullA.testSepAxis(Worldnormal1, hullB,posA,quatA,posB,quatB);
  8675. if(d===false){
  8676. return false;
  8677. }
  8678. if(d<dmin){
  8679. dmin = d;
  8680. target.copy(Worldnormal1);
  8681. }
  8682. }
  8683. } else {
  8684. // Test unique axes in B
  8685. for(var i = 0; i !== hullB.uniqueAxes.length; i++){
  8686. quatB.vmult(hullB.uniqueAxes[i],Worldnormal1);
  8687. curPlaneTests++;
  8688. var d = hullA.testSepAxis(Worldnormal1, hullB,posA,quatA,posB,quatB);
  8689. if(d===false){
  8690. return false;
  8691. }
  8692. if(d<dmin){
  8693. dmin = d;
  8694. target.copy(Worldnormal1);
  8695. }
  8696. }
  8697. }
  8698. // Test edges
  8699. for(var e0=0; e0 !== hullA.uniqueEdges.length; e0++){
  8700. // Get world edge
  8701. quatA.vmult(hullA.uniqueEdges[e0],worldEdge0);
  8702. for(var e1=0; e1 !== hullB.uniqueEdges.length; e1++){
  8703. // Get world edge 2
  8704. quatB.vmult(hullB.uniqueEdges[e1], worldEdge1);
  8705. worldEdge0.cross(worldEdge1,Cross);
  8706. if(!Cross.almostZero()){
  8707. Cross.normalize();
  8708. var dist = hullA.testSepAxis(Cross, hullB, posA, quatA, posB, quatB);
  8709. if(dist === false){
  8710. return false;
  8711. }
  8712. if(dist < dmin){
  8713. dmin = dist;
  8714. target.copy(Cross);
  8715. }
  8716. }
  8717. }
  8718. }
  8719. posB.vsub(posA,deltaC);
  8720. if((deltaC.dot(target))>0.0){
  8721. target.negate(target);
  8722. }
  8723. return true;
  8724. };
  8725. var maxminA=[], maxminB=[];
  8726. /**
  8727. * Test separating axis against two hulls. Both hulls are projected onto the axis and the overlap size is returned if there is one.
  8728. * @method testSepAxis
  8729. * @param {Vec3} axis
  8730. * @param {ConvexPolyhedron} hullB
  8731. * @param {Vec3} posA
  8732. * @param {Quaternion} quatA
  8733. * @param {Vec3} posB
  8734. * @param {Quaternion} quatB
  8735. * @return {number} The overlap depth, or FALSE if no penetration.
  8736. */
  8737. ConvexPolyhedron.prototype.testSepAxis = function(axis, hullB, posA, quatA, posB, quatB){
  8738. var hullA=this;
  8739. ConvexPolyhedron.project(hullA, axis, posA, quatA, maxminA);
  8740. ConvexPolyhedron.project(hullB, axis, posB, quatB, maxminB);
  8741. var maxA = maxminA[0];
  8742. var minA = maxminA[1];
  8743. var maxB = maxminB[0];
  8744. var minB = maxminB[1];
  8745. if(maxA<minB || maxB<minA){
  8746. return false; // Separated
  8747. }
  8748. var d0 = maxA - minB;
  8749. var d1 = maxB - minA;
  8750. var depth = d0<d1 ? d0:d1;
  8751. return depth;
  8752. };
  8753. var cli_aabbmin = new Vec3(),
  8754. cli_aabbmax = new Vec3();
  8755. /**
  8756. * @method calculateLocalInertia
  8757. * @param {Number} mass
  8758. * @param {Vec3} target
  8759. */
  8760. ConvexPolyhedron.prototype.calculateLocalInertia = function(mass,target){
  8761. // Approximate with box inertia
  8762. // Exact inertia calculation is overkill, but see http://geometrictools.com/Documentation/PolyhedralMassProperties.pdf for the correct way to do it
  8763. this.computeLocalAABB(cli_aabbmin,cli_aabbmax);
  8764. var x = cli_aabbmax.x - cli_aabbmin.x,
  8765. y = cli_aabbmax.y - cli_aabbmin.y,
  8766. z = cli_aabbmax.z - cli_aabbmin.z;
  8767. target.x = 1.0 / 12.0 * mass * ( 2*y*2*y + 2*z*2*z );
  8768. target.y = 1.0 / 12.0 * mass * ( 2*x*2*x + 2*z*2*z );
  8769. target.z = 1.0 / 12.0 * mass * ( 2*y*2*y + 2*x*2*x );
  8770. };
  8771. /**
  8772. * @method getPlaneConstantOfFace
  8773. * @param {Number} face_i Index of the face
  8774. * @return {Number}
  8775. */
  8776. ConvexPolyhedron.prototype.getPlaneConstantOfFace = function(face_i){
  8777. var f = this.faces[face_i];
  8778. var n = this.faceNormals[face_i];
  8779. var v = this.vertices[f[0]];
  8780. var c = -n.dot(v);
  8781. return c;
  8782. };
  8783. /**
  8784. * Clip a face against a hull.
  8785. * @method clipFaceAgainstHull
  8786. * @param {Vec3} separatingNormal
  8787. * @param {Vec3} posA
  8788. * @param {Quaternion} quatA
  8789. * @param {Array} worldVertsB1 An array of Vec3 with vertices in the world frame.
  8790. * @param {Number} minDist Distance clamping
  8791. * @param {Number} maxDist
  8792. * @param Array result Array to store resulting contact points in. Will be objects with properties: point, depth, normal. These are represented in world coordinates.
  8793. */
  8794. var cfah_faceANormalWS = new Vec3(),
  8795. cfah_edge0 = new Vec3(),
  8796. cfah_WorldEdge0 = new Vec3(),
  8797. cfah_worldPlaneAnormal1 = new Vec3(),
  8798. cfah_planeNormalWS1 = new Vec3(),
  8799. cfah_worldA1 = new Vec3(),
  8800. cfah_localPlaneNormal = new Vec3(),
  8801. cfah_planeNormalWS = new Vec3();
  8802. ConvexPolyhedron.prototype.clipFaceAgainstHull = function(separatingNormal, posA, quatA, worldVertsB1, minDist, maxDist,result){
  8803. var faceANormalWS = cfah_faceANormalWS,
  8804. edge0 = cfah_edge0,
  8805. WorldEdge0 = cfah_WorldEdge0,
  8806. worldPlaneAnormal1 = cfah_worldPlaneAnormal1,
  8807. planeNormalWS1 = cfah_planeNormalWS1,
  8808. worldA1 = cfah_worldA1,
  8809. localPlaneNormal = cfah_localPlaneNormal,
  8810. planeNormalWS = cfah_planeNormalWS;
  8811. var hullA = this;
  8812. var worldVertsB2 = [];
  8813. var pVtxIn = worldVertsB1;
  8814. var pVtxOut = worldVertsB2;
  8815. // Find the face with normal closest to the separating axis
  8816. var closestFaceA = -1;
  8817. var dmin = Number.MAX_VALUE;
  8818. for(var face=0; face<hullA.faces.length; face++){
  8819. faceANormalWS.copy(hullA.faceNormals[face]);
  8820. quatA.vmult(faceANormalWS,faceANormalWS);
  8821. //posA.vadd(faceANormalWS,faceANormalWS);
  8822. var d = faceANormalWS.dot(separatingNormal);
  8823. if (d < dmin){
  8824. dmin = d;
  8825. closestFaceA = face;
  8826. }
  8827. }
  8828. if (closestFaceA < 0){
  8829. // console.log("--- did not find any closest face... ---");
  8830. return;
  8831. }
  8832. //console.log("closest A: ",closestFaceA);
  8833. // Get the face and construct connected faces
  8834. var polyA = hullA.faces[closestFaceA];
  8835. polyA.connectedFaces = [];
  8836. for(var i=0; i<hullA.faces.length; i++){
  8837. for(var j=0; j<hullA.faces[i].length; j++){
  8838. if(polyA.indexOf(hullA.faces[i][j])!==-1 /* Sharing a vertex*/ && i!==closestFaceA /* Not the one we are looking for connections from */ && polyA.connectedFaces.indexOf(i)===-1 /* Not already added */ ){
  8839. polyA.connectedFaces.push(i);
  8840. }
  8841. }
  8842. }
  8843. // Clip the polygon to the back of the planes of all faces of hull A, that are adjacent to the witness face
  8844. var numContacts = pVtxIn.length;
  8845. var numVerticesA = polyA.length;
  8846. var res = [];
  8847. for(var e0=0; e0<numVerticesA; e0++){
  8848. var a = hullA.vertices[polyA[e0]];
  8849. var b = hullA.vertices[polyA[(e0+1)%numVerticesA]];
  8850. a.vsub(b,edge0);
  8851. WorldEdge0.copy(edge0);
  8852. quatA.vmult(WorldEdge0,WorldEdge0);
  8853. posA.vadd(WorldEdge0,WorldEdge0);
  8854. worldPlaneAnormal1.copy(this.faceNormals[closestFaceA]);//transA.getBasis()* btVector3(polyA.m_plane[0],polyA.m_plane[1],polyA.m_plane[2]);
  8855. quatA.vmult(worldPlaneAnormal1,worldPlaneAnormal1);
  8856. posA.vadd(worldPlaneAnormal1,worldPlaneAnormal1);
  8857. WorldEdge0.cross(worldPlaneAnormal1,planeNormalWS1);
  8858. planeNormalWS1.negate(planeNormalWS1);
  8859. worldA1.copy(a);
  8860. quatA.vmult(worldA1,worldA1);
  8861. posA.vadd(worldA1,worldA1);
  8862. var planeEqWS1 = -worldA1.dot(planeNormalWS1);
  8863. var planeEqWS;
  8864. if(true){
  8865. var otherFace = polyA.connectedFaces[e0];
  8866. localPlaneNormal.copy(this.faceNormals[otherFace]);
  8867. var localPlaneEq = this.getPlaneConstantOfFace(otherFace);
  8868. planeNormalWS.copy(localPlaneNormal);
  8869. quatA.vmult(planeNormalWS,planeNormalWS);
  8870. //posA.vadd(planeNormalWS,planeNormalWS);
  8871. var planeEqWS = localPlaneEq - planeNormalWS.dot(posA);
  8872. } else {
  8873. planeNormalWS.copy(planeNormalWS1);
  8874. planeEqWS = planeEqWS1;
  8875. }
  8876. // Clip face against our constructed plane
  8877. this.clipFaceAgainstPlane(pVtxIn, pVtxOut, planeNormalWS, planeEqWS);
  8878. // Throw away all clipped points, but save the reamining until next clip
  8879. while(pVtxIn.length){
  8880. pVtxIn.shift();
  8881. }
  8882. while(pVtxOut.length){
  8883. pVtxIn.push(pVtxOut.shift());
  8884. }
  8885. }
  8886. //console.log("Resulting points after clip:",pVtxIn);
  8887. // only keep contact points that are behind the witness face
  8888. localPlaneNormal.copy(this.faceNormals[closestFaceA]);
  8889. var localPlaneEq = this.getPlaneConstantOfFace(closestFaceA);
  8890. planeNormalWS.copy(localPlaneNormal);
  8891. quatA.vmult(planeNormalWS,planeNormalWS);
  8892. var planeEqWS = localPlaneEq - planeNormalWS.dot(posA);
  8893. for (var i=0; i<pVtxIn.length; i++){
  8894. var depth = planeNormalWS.dot(pVtxIn[i]) + planeEqWS; //???
  8895. /*console.log("depth calc from normal=",planeNormalWS.toString()," and constant "+planeEqWS+" and vertex ",pVtxIn[i].toString()," gives "+depth);*/
  8896. if (depth <=minDist){
  8897. console.log("clamped: depth="+depth+" to minDist="+(minDist+""));
  8898. depth = minDist;
  8899. }
  8900. if (depth <=maxDist){
  8901. var point = pVtxIn[i];
  8902. if(depth<=0){
  8903. /*console.log("Got contact point ",point.toString(),
  8904. ", depth=",depth,
  8905. "contact normal=",separatingNormal.toString(),
  8906. "plane",planeNormalWS.toString(),
  8907. "planeConstant",planeEqWS);*/
  8908. var p = {
  8909. point:point,
  8910. normal:planeNormalWS,
  8911. depth: depth,
  8912. };
  8913. result.push(p);
  8914. }
  8915. }
  8916. }
  8917. };
  8918. /**
  8919. * Clip a face in a hull against the back of a plane.
  8920. * @method clipFaceAgainstPlane
  8921. * @param {Array} inVertices
  8922. * @param {Array} outVertices
  8923. * @param {Vec3} planeNormal
  8924. * @param {Number} planeConstant The constant in the mathematical plane equation
  8925. */
  8926. ConvexPolyhedron.prototype.clipFaceAgainstPlane = function(inVertices,outVertices, planeNormal, planeConstant){
  8927. var n_dot_first, n_dot_last;
  8928. var numVerts = inVertices.length;
  8929. if(numVerts < 2){
  8930. return outVertices;
  8931. }
  8932. var firstVertex = inVertices[inVertices.length-1],
  8933. lastVertex = inVertices[0];
  8934. n_dot_first = planeNormal.dot(firstVertex) + planeConstant;
  8935. for(var vi = 0; vi < numVerts; vi++){
  8936. lastVertex = inVertices[vi];
  8937. n_dot_last = planeNormal.dot(lastVertex) + planeConstant;
  8938. if(n_dot_first < 0){
  8939. if(n_dot_last < 0){
  8940. // Start < 0, end < 0, so output lastVertex
  8941. var newv = new Vec3();
  8942. newv.copy(lastVertex);
  8943. outVertices.push(newv);
  8944. } else {
  8945. // Start < 0, end >= 0, so output intersection
  8946. var newv = new Vec3();
  8947. firstVertex.lerp(lastVertex,
  8948. n_dot_first / (n_dot_first - n_dot_last),
  8949. newv);
  8950. outVertices.push(newv);
  8951. }
  8952. } else {
  8953. if(n_dot_last<0){
  8954. // Start >= 0, end < 0 so output intersection and end
  8955. var newv = new Vec3();
  8956. firstVertex.lerp(lastVertex,
  8957. n_dot_first / (n_dot_first - n_dot_last),
  8958. newv);
  8959. outVertices.push(newv);
  8960. outVertices.push(lastVertex);
  8961. }
  8962. }
  8963. firstVertex = lastVertex;
  8964. n_dot_first = n_dot_last;
  8965. }
  8966. return outVertices;
  8967. };
  8968. // Updates .worldVertices and sets .worldVerticesNeedsUpdate to false.
  8969. ConvexPolyhedron.prototype.computeWorldVertices = function(position,quat){
  8970. var N = this.vertices.length;
  8971. while(this.worldVertices.length < N){
  8972. this.worldVertices.push( new Vec3() );
  8973. }
  8974. var verts = this.vertices,
  8975. worldVerts = this.worldVertices;
  8976. for(var i=0; i!==N; i++){
  8977. quat.vmult( verts[i] , worldVerts[i] );
  8978. position.vadd( worldVerts[i] , worldVerts[i] );
  8979. }
  8980. this.worldVerticesNeedsUpdate = false;
  8981. };
  8982. var computeLocalAABB_worldVert = new Vec3();
  8983. ConvexPolyhedron.prototype.computeLocalAABB = function(aabbmin,aabbmax){
  8984. var n = this.vertices.length,
  8985. vertices = this.vertices,
  8986. worldVert = computeLocalAABB_worldVert;
  8987. aabbmin.set(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  8988. aabbmax.set(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
  8989. for(var i=0; i<n; i++){
  8990. var v = vertices[i];
  8991. if (v.x < aabbmin.x){
  8992. aabbmin.x = v.x;
  8993. } else if(v.x > aabbmax.x){
  8994. aabbmax.x = v.x;
  8995. }
  8996. if (v.y < aabbmin.y){
  8997. aabbmin.y = v.y;
  8998. } else if(v.y > aabbmax.y){
  8999. aabbmax.y = v.y;
  9000. }
  9001. if (v.z < aabbmin.z){
  9002. aabbmin.z = v.z;
  9003. } else if(v.z > aabbmax.z){
  9004. aabbmax.z = v.z;
  9005. }
  9006. }
  9007. };
  9008. /**
  9009. * Updates .worldVertices and sets .worldVerticesNeedsUpdate to false.
  9010. * @method computeWorldFaceNormals
  9011. * @param {Quaternion} quat
  9012. */
  9013. ConvexPolyhedron.prototype.computeWorldFaceNormals = function(quat){
  9014. var N = this.faceNormals.length;
  9015. while(this.worldFaceNormals.length < N){
  9016. this.worldFaceNormals.push( new Vec3() );
  9017. }
  9018. var normals = this.faceNormals,
  9019. worldNormals = this.worldFaceNormals;
  9020. for(var i=0; i!==N; i++){
  9021. quat.vmult( normals[i] , worldNormals[i] );
  9022. }
  9023. this.worldFaceNormalsNeedsUpdate = false;
  9024. };
  9025. /**
  9026. * @method updateBoundingSphereRadius
  9027. */
  9028. ConvexPolyhedron.prototype.updateBoundingSphereRadius = function(){
  9029. // Assume points are distributed with local (0,0,0) as center
  9030. var max2 = 0;
  9031. var verts = this.vertices;
  9032. for(var i=0, N=verts.length; i!==N; i++) {
  9033. var norm2 = verts[i].norm2();
  9034. if(norm2 > max2){
  9035. max2 = norm2;
  9036. }
  9037. }
  9038. this.boundingSphereRadius = Math.sqrt(max2);
  9039. };
  9040. var tempWorldVertex = new Vec3();
  9041. /**
  9042. * @method calculateWorldAABB
  9043. * @param {Vec3} pos
  9044. * @param {Quaternion} quat
  9045. * @param {Vec3} min
  9046. * @param {Vec3} max
  9047. */
  9048. ConvexPolyhedron.prototype.calculateWorldAABB = function(pos,quat,min,max){
  9049. var n = this.vertices.length, verts = this.vertices;
  9050. var minx,miny,minz,maxx,maxy,maxz;
  9051. for(var i=0; i<n; i++){
  9052. tempWorldVertex.copy(verts[i]);
  9053. quat.vmult(tempWorldVertex,tempWorldVertex);
  9054. pos.vadd(tempWorldVertex,tempWorldVertex);
  9055. var v = tempWorldVertex;
  9056. if (v.x < minx || minx===undefined){
  9057. minx = v.x;
  9058. } else if(v.x > maxx || maxx===undefined){
  9059. maxx = v.x;
  9060. }
  9061. if (v.y < miny || miny===undefined){
  9062. miny = v.y;
  9063. } else if(v.y > maxy || maxy===undefined){
  9064. maxy = v.y;
  9065. }
  9066. if (v.z < minz || minz===undefined){
  9067. minz = v.z;
  9068. } else if(v.z > maxz || maxz===undefined){
  9069. maxz = v.z;
  9070. }
  9071. }
  9072. min.set(minx,miny,minz);
  9073. max.set(maxx,maxy,maxz);
  9074. };
  9075. /**
  9076. * Get approximate convex volume
  9077. * @method volume
  9078. * @return {Number}
  9079. */
  9080. ConvexPolyhedron.prototype.volume = function(){
  9081. return 4.0 * Math.PI * this.boundingSphereRadius / 3.0;
  9082. };
  9083. /**
  9084. * Get an average of all the vertices positions
  9085. * @method getAveragePointLocal
  9086. * @param {Vec3} target
  9087. * @return {Vec3}
  9088. */
  9089. ConvexPolyhedron.prototype.getAveragePointLocal = function(target){
  9090. target = target || new Vec3();
  9091. var n = this.vertices.length,
  9092. verts = this.vertices;
  9093. for(var i=0; i<n; i++){
  9094. target.vadd(verts[i],target);
  9095. }
  9096. target.mult(1/n,target);
  9097. return target;
  9098. };
  9099. /**
  9100. * Transform all local points. Will change the .vertices
  9101. * @method transformAllPoints
  9102. * @param {Vec3} offset
  9103. * @param {Quaternion} quat
  9104. */
  9105. ConvexPolyhedron.prototype.transformAllPoints = function(offset,quat){
  9106. var n = this.vertices.length,
  9107. verts = this.vertices;
  9108. // Apply rotation
  9109. if(quat){
  9110. // Rotate vertices
  9111. for(var i=0; i<n; i++){
  9112. var v = verts[i];
  9113. quat.vmult(v,v);
  9114. }
  9115. // Rotate face normals
  9116. for(var i=0; i<this.faceNormals.length; i++){
  9117. var v = this.faceNormals[i];
  9118. quat.vmult(v,v);
  9119. }
  9120. /*
  9121. // Rotate edges
  9122. for(var i=0; i<this.uniqueEdges.length; i++){
  9123. var v = this.uniqueEdges[i];
  9124. quat.vmult(v,v);
  9125. }*/
  9126. }
  9127. // Apply offset
  9128. if(offset){
  9129. for(var i=0; i<n; i++){
  9130. var v = verts[i];
  9131. v.vadd(offset,v);
  9132. }
  9133. }
  9134. };
  9135. /**
  9136. * Checks whether p is inside the polyhedra. Must be in local coords. The point lies outside of the convex hull of the other points if and only if the direction of all the vectors from it to those other points are on less than one half of a sphere around it.
  9137. * @method pointIsInside
  9138. * @param {Vec3} p A point given in local coordinates
  9139. * @return {Boolean}
  9140. */
  9141. var ConvexPolyhedron_pointIsInside = new Vec3();
  9142. var ConvexPolyhedron_vToP = new Vec3();
  9143. var ConvexPolyhedron_vToPointInside = new Vec3();
  9144. ConvexPolyhedron.prototype.pointIsInside = function(p){
  9145. var n = this.vertices.length,
  9146. verts = this.vertices,
  9147. faces = this.faces,
  9148. normals = this.faceNormals;
  9149. var positiveResult = null;
  9150. var N = this.faces.length;
  9151. var pointInside = ConvexPolyhedron_pointIsInside;
  9152. this.getAveragePointLocal(pointInside);
  9153. for(var i=0; i<N; i++){
  9154. var numVertices = this.faces[i].length;
  9155. var n = normals[i];
  9156. var v = verts[faces[i][0]]; // We only need one point in the face
  9157. // This dot product determines which side of the edge the point is
  9158. var vToP = ConvexPolyhedron_vToP;
  9159. p.vsub(v,vToP);
  9160. var r1 = n.dot(vToP);
  9161. var vToPointInside = ConvexPolyhedron_vToPointInside;
  9162. pointInside.vsub(v,vToPointInside);
  9163. var r2 = n.dot(vToPointInside);
  9164. if((r1<0 && r2>0) || (r1>0 && r2<0)){
  9165. return false; // Encountered some other sign. Exit.
  9166. } else {
  9167. }
  9168. }
  9169. // If we got here, all dot products were of the same sign.
  9170. return positiveResult ? 1 : -1;
  9171. };
  9172. /**
  9173. * Get max and min dot product of a convex hull at position (pos,quat) projected onto an axis. Results are saved in the array maxmin.
  9174. * @static
  9175. * @method project
  9176. * @param {ConvexPolyhedron} hull
  9177. * @param {Vec3} axis
  9178. * @param {Vec3} pos
  9179. * @param {Quaternion} quat
  9180. * @param {array} result result[0] and result[1] will be set to maximum and minimum, respectively.
  9181. */
  9182. var project_worldVertex = new Vec3();
  9183. var project_localAxis = new Vec3();
  9184. var project_localOrigin = new Vec3();
  9185. ConvexPolyhedron.project = function(hull, axis, pos, quat, result){
  9186. var n = hull.vertices.length,
  9187. worldVertex = project_worldVertex,
  9188. localAxis = project_localAxis,
  9189. max = 0,
  9190. min = 0,
  9191. localOrigin = project_localOrigin,
  9192. vs = hull.vertices;
  9193. localOrigin.setZero();
  9194. // Transform the axis to local
  9195. Transform.vectorToLocalFrame(pos, quat, axis, localAxis);
  9196. Transform.pointToLocalFrame(pos, quat, localOrigin, localOrigin);
  9197. var add = localOrigin.dot(localAxis);
  9198. min = max = vs[0].dot(localAxis);
  9199. for(var i = 1; i < n; i++){
  9200. var val = vs[i].dot(localAxis);
  9201. if(val > max){
  9202. max = val;
  9203. }
  9204. if(val < min){
  9205. min = val;
  9206. }
  9207. }
  9208. min -= add;
  9209. max -= add;
  9210. if(min > max){
  9211. // Inconsistent - swap
  9212. var temp = min;
  9213. min = max;
  9214. max = temp;
  9215. }
  9216. // Output
  9217. result[0] = max;
  9218. result[1] = min;
  9219. };
  9220. },{"../math/Quaternion":44,"../math/Transform":45,"../math/Vec3":46,"./Shape":59}],55:[function(require,module,exports){
  9221. module.exports = Cylinder;
  9222. var Shape = require('./Shape');
  9223. var Vec3 = require('../math/Vec3');
  9224. var Quaternion = require('../math/Quaternion');
  9225. var ConvexPolyhedron = require('./ConvexPolyhedron');
  9226. /**
  9227. * @class Cylinder
  9228. * @constructor
  9229. * @extends ConvexPolyhedron
  9230. * @author schteppe / https://github.com/schteppe
  9231. * @param {Number} radiusTop
  9232. * @param {Number} radiusBottom
  9233. * @param {Number} height
  9234. * @param {Number} numSegments The number of segments to build the cylinder out of
  9235. */
  9236. function Cylinder( radiusTop, radiusBottom, height , numSegments ) {
  9237. var N = numSegments,
  9238. verts = [],
  9239. axes = [],
  9240. faces = [],
  9241. bottomface = [],
  9242. topface = [],
  9243. cos = Math.cos,
  9244. sin = Math.sin;
  9245. // First bottom point
  9246. verts.push(new Vec3(radiusBottom*cos(0),
  9247. radiusBottom*sin(0),
  9248. -height*0.5));
  9249. bottomface.push(0);
  9250. // First top point
  9251. verts.push(new Vec3(radiusTop*cos(0),
  9252. radiusTop*sin(0),
  9253. height*0.5));
  9254. topface.push(1);
  9255. for(var i=0; i<N; i++){
  9256. var theta = 2*Math.PI/N * (i+1);
  9257. var thetaN = 2*Math.PI/N * (i+0.5);
  9258. if(i<N-1){
  9259. // Bottom
  9260. verts.push(new Vec3(radiusBottom*cos(theta),
  9261. radiusBottom*sin(theta),
  9262. -height*0.5));
  9263. bottomface.push(2*i+2);
  9264. // Top
  9265. verts.push(new Vec3(radiusTop*cos(theta),
  9266. radiusTop*sin(theta),
  9267. height*0.5));
  9268. topface.push(2*i+3);
  9269. // Face
  9270. faces.push([2*i+2, 2*i+3, 2*i+1,2*i]);
  9271. } else {
  9272. faces.push([0,1, 2*i+1, 2*i]); // Connect
  9273. }
  9274. // Axis: we can cut off half of them if we have even number of segments
  9275. if(N % 2 === 1 || i < N / 2){
  9276. axes.push(new Vec3(cos(thetaN), sin(thetaN), 0));
  9277. }
  9278. }
  9279. faces.push(topface);
  9280. axes.push(new Vec3(0,0,1));
  9281. // Reorder bottom face
  9282. var temp = [];
  9283. for(var i=0; i<bottomface.length; i++){
  9284. temp.push(bottomface[bottomface.length - i - 1]);
  9285. }
  9286. faces.push(temp);
  9287. this.type = Shape.types.CONVEXPOLYHEDRON;
  9288. ConvexPolyhedron.call( this, verts, faces, axes );
  9289. }
  9290. Cylinder.prototype = new ConvexPolyhedron();
  9291. },{"../math/Quaternion":44,"../math/Vec3":46,"./ConvexPolyhedron":54,"./Shape":59}],56:[function(require,module,exports){
  9292. var Shape = require('./Shape');
  9293. var ConvexPolyhedron = require('./ConvexPolyhedron');
  9294. var Vec3 = require('../math/Vec3');
  9295. var Utils = require('../utils/Utils');
  9296. module.exports = Heightfield;
  9297. /**
  9298. * Heightfield shape class. Height data is given as an array. These data points are spread out evenly with a given distance.
  9299. * @class Heightfield
  9300. * @extends Shape
  9301. * @constructor
  9302. * @param {Array} data An array of Y values that will be used to construct the terrain.
  9303. * @param {object} options
  9304. * @param {Number} [options.minValue] Minimum value of the data points in the data array. Will be computed automatically if not given.
  9305. * @param {Number} [options.maxValue] Maximum value.
  9306. * @param {Number} [options.elementSize=0.1] World spacing between the data points in X direction.
  9307. * @todo Should be possible to use along all axes, not just y
  9308. * @todo should be possible to scale along all axes
  9309. *
  9310. * @example
  9311. * // Generate some height data (y-values).
  9312. * var data = [];
  9313. * for(var i = 0; i < 1000; i++){
  9314. * var y = 0.5 * Math.cos(0.2 * i);
  9315. * data.push(y);
  9316. * }
  9317. *
  9318. * // Create the heightfield shape
  9319. * var heightfieldShape = new Heightfield(data, {
  9320. * elementSize: 1 // Distance between the data points in X and Y directions
  9321. * });
  9322. * var heightfieldBody = new Body();
  9323. * heightfieldBody.addShape(heightfieldShape);
  9324. * world.addBody(heightfieldBody);
  9325. */
  9326. function Heightfield(data, options){
  9327. options = Utils.defaults(options, {
  9328. maxValue : null,
  9329. minValue : null,
  9330. elementSize : 1
  9331. });
  9332. /**
  9333. * An array of numbers, or height values, that are spread out along the x axis.
  9334. * @property {array} data
  9335. */
  9336. this.data = data;
  9337. /**
  9338. * Max value of the data
  9339. * @property {number} maxValue
  9340. */
  9341. this.maxValue = options.maxValue;
  9342. /**
  9343. * Max value of the data
  9344. * @property {number} minValue
  9345. */
  9346. this.minValue = options.minValue;
  9347. /**
  9348. * The width of each element
  9349. * @property {number} elementSize
  9350. * @todo elementSizeX and Y
  9351. */
  9352. this.elementSize = options.elementSize;
  9353. if(options.minValue === null){
  9354. this.updateMinValue();
  9355. }
  9356. if(options.maxValue === null){
  9357. this.updateMaxValue();
  9358. }
  9359. this.cacheEnabled = true;
  9360. Shape.call(this);
  9361. this.pillarConvex = new ConvexPolyhedron();
  9362. this.pillarOffset = new Vec3();
  9363. this.type = Shape.types.HEIGHTFIELD;
  9364. this.updateBoundingSphereRadius();
  9365. // "i_j_isUpper" => { convex: ..., offset: ... }
  9366. // for example:
  9367. // _cachedPillars["0_2_1"]
  9368. this._cachedPillars = {};
  9369. }
  9370. Heightfield.prototype = new Shape();
  9371. /**
  9372. * Call whenever you change the data array.
  9373. * @method update
  9374. */
  9375. Heightfield.prototype.update = function(){
  9376. this._cachedPillars = {};
  9377. };
  9378. /**
  9379. * Update the .minValue property
  9380. * @method updateMinValue
  9381. */
  9382. Heightfield.prototype.updateMinValue = function(){
  9383. var data = this.data;
  9384. var minValue = data[0][0];
  9385. for(var i=0; i !== data.length; i++){
  9386. for(var j=0; j !== data[i].length; j++){
  9387. var v = data[i][j];
  9388. if(v < minValue){
  9389. minValue = v;
  9390. }
  9391. }
  9392. }
  9393. this.minValue = minValue;
  9394. };
  9395. /**
  9396. * Update the .maxValue property
  9397. * @method updateMaxValue
  9398. */
  9399. Heightfield.prototype.updateMaxValue = function(){
  9400. var data = this.data;
  9401. var maxValue = data[0][0];
  9402. for(var i=0; i !== data.length; i++){
  9403. for(var j=0; j !== data[i].length; j++){
  9404. var v = data[i][j];
  9405. if(v > maxValue){
  9406. maxValue = v;
  9407. }
  9408. }
  9409. }
  9410. this.maxValue = maxValue;
  9411. };
  9412. /**
  9413. * Set the height value at an index. Don't forget to update maxValue and minValue after you're done.
  9414. * @method setHeightValueAtIndex
  9415. * @param {integer} xi
  9416. * @param {integer} yi
  9417. * @param {number} value
  9418. */
  9419. Heightfield.prototype.setHeightValueAtIndex = function(xi, yi, value){
  9420. var data = this.data;
  9421. data[xi][yi] = value;
  9422. // Invalidate cache
  9423. this.clearCachedConvexTrianglePillar(xi, yi, false);
  9424. if(xi > 0){
  9425. this.clearCachedConvexTrianglePillar(xi - 1, yi, true);
  9426. this.clearCachedConvexTrianglePillar(xi - 1, yi, false);
  9427. }
  9428. if(yi > 0){
  9429. this.clearCachedConvexTrianglePillar(xi, yi - 1, true);
  9430. this.clearCachedConvexTrianglePillar(xi, yi - 1, false);
  9431. }
  9432. if(yi > 0 && xi > 0){
  9433. this.clearCachedConvexTrianglePillar(xi - 1, yi - 1, true);
  9434. }
  9435. };
  9436. /**
  9437. * Get max/min in a rectangle in the matrix data
  9438. * @method getRectMinMax
  9439. * @param {integer} iMinX
  9440. * @param {integer} iMinY
  9441. * @param {integer} iMaxX
  9442. * @param {integer} iMaxY
  9443. * @param {array} [result] An array to store the results in.
  9444. * @return {array} The result array, if it was passed in. Minimum will be at position 0 and max at 1.
  9445. */
  9446. Heightfield.prototype.getRectMinMax = function (iMinX, iMinY, iMaxX, iMaxY, result) {
  9447. result = result || [];
  9448. // Get max and min of the data
  9449. var data = this.data,
  9450. max = this.minValue; // Set first value
  9451. for(var i = iMinX; i <= iMaxX; i++){
  9452. for(var j = iMinY; j <= iMaxY; j++){
  9453. var height = data[i][j];
  9454. if(height > max){
  9455. max = height;
  9456. }
  9457. }
  9458. }
  9459. result[0] = this.minValue;
  9460. result[1] = max;
  9461. };
  9462. /**
  9463. * Get the index of a local position on the heightfield. The indexes indicate the rectangles, so if your terrain is made of N x N height data points, you will have rectangle indexes ranging from 0 to N-1.
  9464. * @method getIndexOfPosition
  9465. * @param {number} x
  9466. * @param {number} y
  9467. * @param {array} result Two-element array
  9468. * @param {boolean} clamp If the position should be clamped to the heightfield edge.
  9469. * @return {boolean}
  9470. */
  9471. Heightfield.prototype.getIndexOfPosition = function (x, y, result, clamp) {
  9472. // Get the index of the data points to test against
  9473. var w = this.elementSize;
  9474. var data = this.data;
  9475. var xi = Math.floor(x / w);
  9476. var yi = Math.floor(y / w);
  9477. result[0] = xi;
  9478. result[1] = yi;
  9479. if(clamp){
  9480. // Clamp index to edges
  9481. if(xi < 0){ xi = 0; }
  9482. if(yi < 0){ yi = 0; }
  9483. if(xi >= data.length - 1){ xi = data.length - 1; }
  9484. if(yi >= data[0].length - 1){ yi = data[0].length - 1; }
  9485. }
  9486. // Bail out if we are out of the terrain
  9487. if(xi < 0 || yi < 0 || xi >= data.length-1 || yi >= data[0].length-1){
  9488. return false;
  9489. }
  9490. return true;
  9491. };
  9492. var getHeightAt_idx = [];
  9493. var getHeightAt_weights = new Vec3();
  9494. var getHeightAt_a = new Vec3();
  9495. var getHeightAt_b = new Vec3();
  9496. var getHeightAt_c = new Vec3();
  9497. Heightfield.prototype.getTriangleAt = function(x, y, edgeClamp, a, b, c){
  9498. var idx = getHeightAt_idx;
  9499. this.getIndexOfPosition(x, y, idx, edgeClamp);
  9500. var xi = idx[0];
  9501. var yi = idx[1];
  9502. var data = this.data;
  9503. if(edgeClamp){
  9504. xi = Math.min(data.length - 2, Math.max(0, xi));
  9505. yi = Math.min(data[0].length - 2, Math.max(0, yi));
  9506. }
  9507. var elementSize = this.elementSize;
  9508. var lowerDist2 = Math.pow(x / elementSize - xi, 2) + Math.pow(y / elementSize - yi, 2);
  9509. var upperDist2 = Math.pow(x / elementSize - (xi + 1), 2) + Math.pow(y / elementSize - (yi + 1), 2);
  9510. var upper = lowerDist2 > upperDist2;
  9511. this.getTriangle(xi, yi, upper, a, b, c);
  9512. return upper;
  9513. };
  9514. var getNormalAt_a = new Vec3();
  9515. var getNormalAt_b = new Vec3();
  9516. var getNormalAt_c = new Vec3();
  9517. var getNormalAt_e0 = new Vec3();
  9518. var getNormalAt_e1 = new Vec3();
  9519. Heightfield.prototype.getNormalAt = function(x, y, edgeClamp, result){
  9520. var a = getNormalAt_a;
  9521. var b = getNormalAt_b;
  9522. var c = getNormalAt_c;
  9523. var e0 = getNormalAt_e0;
  9524. var e1 = getNormalAt_e1;
  9525. this.getTriangleAt(x, y, edgeClamp, a, b, c);
  9526. b.vsub(a, e0);
  9527. c.vsub(a, e1);
  9528. e0.cross(e1, result);
  9529. result.normalize();
  9530. };
  9531. /**
  9532. * Get an AABB of a square in the heightfield
  9533. * @param {number} xi
  9534. * @param {number} yi
  9535. * @param {AABB} result
  9536. */
  9537. Heightfield.prototype.getAabbAtIndex = function(xi, yi, result){
  9538. var data = this.data;
  9539. var elementSize = this.elementSize;
  9540. result.lowerBound.set(
  9541. xi * elementSize,
  9542. yi * elementSize,
  9543. data[xi][yi]
  9544. );
  9545. result.upperBound.set(
  9546. (xi + 1) * elementSize,
  9547. (yi + 1) * elementSize,
  9548. data[xi + 1][yi + 1]
  9549. );
  9550. };
  9551. /**
  9552. * Get the height in the heightfield at a given position
  9553. * @param {number} x
  9554. * @param {number} y
  9555. * @param {boolean} edgeClamp
  9556. * @return {number}
  9557. */
  9558. Heightfield.prototype.getHeightAt = function(x, y, edgeClamp){
  9559. var data = this.data;
  9560. var a = getHeightAt_a;
  9561. var b = getHeightAt_b;
  9562. var c = getHeightAt_c;
  9563. var idx = getHeightAt_idx;
  9564. this.getIndexOfPosition(x, y, idx, edgeClamp);
  9565. var xi = idx[0];
  9566. var yi = idx[1];
  9567. if(edgeClamp){
  9568. xi = Math.min(data.length - 2, Math.max(0, xi));
  9569. yi = Math.min(data[0].length - 2, Math.max(0, yi));
  9570. }
  9571. var upper = this.getTriangleAt(x, y, edgeClamp, a, b, c);
  9572. barycentricWeights(x, y, a.x, a.y, b.x, b.y, c.x, c.y, getHeightAt_weights);
  9573. var w = getHeightAt_weights;
  9574. if(upper){
  9575. // Top triangle verts
  9576. return data[xi + 1][yi + 1] * w.x + data[xi][yi + 1] * w.y + data[xi + 1][yi] * w.z;
  9577. } else {
  9578. // Top triangle verts
  9579. return data[xi][yi] * w.x + data[xi + 1][yi] * w.y + data[xi][yi + 1] * w.z;
  9580. }
  9581. };
  9582. // from https://en.wikipedia.org/wiki/Barycentric_coordinate_system
  9583. function barycentricWeights(x, y, ax, ay, bx, by, cx, cy, result){
  9584. result.x = ((by - cy) * (x - cx) + (cx - bx) * (y - cy)) / ((by - cy) * (ax - cx) + (cx - bx) * (ay - cy));
  9585. result.y = ((cy - ay) * (x - cx) + (ax - cx) * (y - cy)) / ((by - cy) * (ax - cx) + (cx - bx) * (ay - cy));
  9586. result.z = 1 - result.x - result.y;
  9587. }
  9588. Heightfield.prototype.getCacheConvexTrianglePillarKey = function(xi, yi, getUpperTriangle){
  9589. return xi + '_' + yi + '_' + (getUpperTriangle ? 1 : 0);
  9590. };
  9591. Heightfield.prototype.getCachedConvexTrianglePillar = function(xi, yi, getUpperTriangle){
  9592. return this._cachedPillars[this.getCacheConvexTrianglePillarKey(xi, yi, getUpperTriangle)];
  9593. };
  9594. Heightfield.prototype.setCachedConvexTrianglePillar = function(xi, yi, getUpperTriangle, convex, offset){
  9595. this._cachedPillars[this.getCacheConvexTrianglePillarKey(xi, yi, getUpperTriangle)] = {
  9596. convex: convex,
  9597. offset: offset
  9598. };
  9599. };
  9600. Heightfield.prototype.clearCachedConvexTrianglePillar = function(xi, yi, getUpperTriangle){
  9601. delete this._cachedPillars[this.getCacheConvexTrianglePillarKey(xi, yi, getUpperTriangle)];
  9602. };
  9603. /**
  9604. * Get a triangle from the heightfield
  9605. * @param {number} xi
  9606. * @param {number} yi
  9607. * @param {boolean} upper
  9608. * @param {Vec3} a
  9609. * @param {Vec3} b
  9610. * @param {Vec3} c
  9611. */
  9612. Heightfield.prototype.getTriangle = function(xi, yi, upper, a, b, c){
  9613. var data = this.data;
  9614. var elementSize = this.elementSize;
  9615. if(upper){
  9616. // Top triangle verts
  9617. a.set(
  9618. (xi + 1) * elementSize,
  9619. (yi + 1) * elementSize,
  9620. data[xi + 1][yi + 1]
  9621. );
  9622. b.set(
  9623. xi * elementSize,
  9624. (yi + 1) * elementSize,
  9625. data[xi][yi + 1]
  9626. );
  9627. c.set(
  9628. (xi + 1) * elementSize,
  9629. yi * elementSize,
  9630. data[xi + 1][yi]
  9631. );
  9632. } else {
  9633. // Top triangle verts
  9634. a.set(
  9635. xi * elementSize,
  9636. yi * elementSize,
  9637. data[xi][yi]
  9638. );
  9639. b.set(
  9640. (xi + 1) * elementSize,
  9641. yi * elementSize,
  9642. data[xi + 1][yi]
  9643. );
  9644. c.set(
  9645. xi * elementSize,
  9646. (yi + 1) * elementSize,
  9647. data[xi][yi + 1]
  9648. );
  9649. }
  9650. };
  9651. /**
  9652. * Get a triangle in the terrain in the form of a triangular convex shape.
  9653. * @method getConvexTrianglePillar
  9654. * @param {integer} i
  9655. * @param {integer} j
  9656. * @param {boolean} getUpperTriangle
  9657. */
  9658. Heightfield.prototype.getConvexTrianglePillar = function(xi, yi, getUpperTriangle){
  9659. var result = this.pillarConvex;
  9660. var offsetResult = this.pillarOffset;
  9661. if(this.cacheEnabled){
  9662. var data = this.getCachedConvexTrianglePillar(xi, yi, getUpperTriangle);
  9663. if(data){
  9664. this.pillarConvex = data.convex;
  9665. this.pillarOffset = data.offset;
  9666. return;
  9667. }
  9668. result = new ConvexPolyhedron();
  9669. offsetResult = new Vec3();
  9670. this.pillarConvex = result;
  9671. this.pillarOffset = offsetResult;
  9672. }
  9673. var data = this.data;
  9674. var elementSize = this.elementSize;
  9675. var faces = result.faces;
  9676. // Reuse verts if possible
  9677. result.vertices.length = 6;
  9678. for (var i = 0; i < 6; i++) {
  9679. if(!result.vertices[i]){
  9680. result.vertices[i] = new Vec3();
  9681. }
  9682. }
  9683. // Reuse faces if possible
  9684. faces.length = 5;
  9685. for (var i = 0; i < 5; i++) {
  9686. if(!faces[i]){
  9687. faces[i] = [];
  9688. }
  9689. }
  9690. var verts = result.vertices;
  9691. var h = (Math.min(
  9692. data[xi][yi],
  9693. data[xi+1][yi],
  9694. data[xi][yi+1],
  9695. data[xi+1][yi+1]
  9696. ) - this.minValue ) / 2 + this.minValue;
  9697. if (!getUpperTriangle) {
  9698. // Center of the triangle pillar - all polygons are given relative to this one
  9699. offsetResult.set(
  9700. (xi + 0.25) * elementSize, // sort of center of a triangle
  9701. (yi + 0.25) * elementSize,
  9702. h // vertical center
  9703. );
  9704. // Top triangle verts
  9705. verts[0].set(
  9706. -0.25 * elementSize,
  9707. -0.25 * elementSize,
  9708. data[xi][yi] - h
  9709. );
  9710. verts[1].set(
  9711. 0.75 * elementSize,
  9712. -0.25 * elementSize,
  9713. data[xi + 1][yi] - h
  9714. );
  9715. verts[2].set(
  9716. -0.25 * elementSize,
  9717. 0.75 * elementSize,
  9718. data[xi][yi + 1] - h
  9719. );
  9720. // bottom triangle verts
  9721. verts[3].set(
  9722. -0.25 * elementSize,
  9723. -0.25 * elementSize,
  9724. -h-1
  9725. );
  9726. verts[4].set(
  9727. 0.75 * elementSize,
  9728. -0.25 * elementSize,
  9729. -h-1
  9730. );
  9731. verts[5].set(
  9732. -0.25 * elementSize,
  9733. 0.75 * elementSize,
  9734. -h-1
  9735. );
  9736. // top triangle
  9737. faces[0][0] = 0;
  9738. faces[0][1] = 1;
  9739. faces[0][2] = 2;
  9740. // bottom triangle
  9741. faces[1][0] = 5;
  9742. faces[1][1] = 4;
  9743. faces[1][2] = 3;
  9744. // -x facing quad
  9745. faces[2][0] = 0;
  9746. faces[2][1] = 2;
  9747. faces[2][2] = 5;
  9748. faces[2][3] = 3;
  9749. // -y facing quad
  9750. faces[3][0] = 1;
  9751. faces[3][1] = 0;
  9752. faces[3][2] = 3;
  9753. faces[3][3] = 4;
  9754. // +xy facing quad
  9755. faces[4][0] = 4;
  9756. faces[4][1] = 5;
  9757. faces[4][2] = 2;
  9758. faces[4][3] = 1;
  9759. } else {
  9760. // Center of the triangle pillar - all polygons are given relative to this one
  9761. offsetResult.set(
  9762. (xi + 0.75) * elementSize, // sort of center of a triangle
  9763. (yi + 0.75) * elementSize,
  9764. h // vertical center
  9765. );
  9766. // Top triangle verts
  9767. verts[0].set(
  9768. 0.25 * elementSize,
  9769. 0.25 * elementSize,
  9770. data[xi + 1][yi + 1] - h
  9771. );
  9772. verts[1].set(
  9773. -0.75 * elementSize,
  9774. 0.25 * elementSize,
  9775. data[xi][yi + 1] - h
  9776. );
  9777. verts[2].set(
  9778. 0.25 * elementSize,
  9779. -0.75 * elementSize,
  9780. data[xi + 1][yi] - h
  9781. );
  9782. // bottom triangle verts
  9783. verts[3].set(
  9784. 0.25 * elementSize,
  9785. 0.25 * elementSize,
  9786. - h-1
  9787. );
  9788. verts[4].set(
  9789. -0.75 * elementSize,
  9790. 0.25 * elementSize,
  9791. - h-1
  9792. );
  9793. verts[5].set(
  9794. 0.25 * elementSize,
  9795. -0.75 * elementSize,
  9796. - h-1
  9797. );
  9798. // Top triangle
  9799. faces[0][0] = 0;
  9800. faces[0][1] = 1;
  9801. faces[0][2] = 2;
  9802. // bottom triangle
  9803. faces[1][0] = 5;
  9804. faces[1][1] = 4;
  9805. faces[1][2] = 3;
  9806. // +x facing quad
  9807. faces[2][0] = 2;
  9808. faces[2][1] = 5;
  9809. faces[2][2] = 3;
  9810. faces[2][3] = 0;
  9811. // +y facing quad
  9812. faces[3][0] = 3;
  9813. faces[3][1] = 4;
  9814. faces[3][2] = 1;
  9815. faces[3][3] = 0;
  9816. // -xy facing quad
  9817. faces[4][0] = 1;
  9818. faces[4][1] = 4;
  9819. faces[4][2] = 5;
  9820. faces[4][3] = 2;
  9821. }
  9822. result.computeNormals();
  9823. result.computeEdges();
  9824. result.updateBoundingSphereRadius();
  9825. this.setCachedConvexTrianglePillar(xi, yi, getUpperTriangle, result, offsetResult);
  9826. };
  9827. Heightfield.prototype.calculateLocalInertia = function(mass, target){
  9828. target = target || new Vec3();
  9829. target.set(0, 0, 0);
  9830. return target;
  9831. };
  9832. Heightfield.prototype.volume = function(){
  9833. return Number.MAX_VALUE; // The terrain is infinite
  9834. };
  9835. Heightfield.prototype.calculateWorldAABB = function(pos, quat, min, max){
  9836. // TODO: do it properly
  9837. min.set(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
  9838. max.set(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  9839. };
  9840. Heightfield.prototype.updateBoundingSphereRadius = function(){
  9841. // Use the bounding box of the min/max values
  9842. var data = this.data,
  9843. s = this.elementSize;
  9844. this.boundingSphereRadius = new Vec3(data.length * s, data[0].length * s, Math.max(Math.abs(this.maxValue), Math.abs(this.minValue))).norm();
  9845. };
  9846. /**
  9847. * Sets the height values from an image. Currently only supported in browser.
  9848. * @method setHeightsFromImage
  9849. * @param {Image} image
  9850. * @param {Vec3} scale
  9851. */
  9852. Heightfield.prototype.setHeightsFromImage = function(image, scale){
  9853. var canvas = document.createElement('canvas');
  9854. canvas.width = image.width;
  9855. canvas.height = image.height;
  9856. var context = canvas.getContext('2d');
  9857. context.drawImage(image, 0, 0);
  9858. var imageData = context.getImageData(0, 0, image.width, image.height);
  9859. var matrix = this.data;
  9860. matrix.length = 0;
  9861. this.elementSize = Math.abs(scale.x) / imageData.width;
  9862. for(var i=0; i<imageData.height; i++){
  9863. var row = [];
  9864. for(var j=0; j<imageData.width; j++){
  9865. var a = imageData.data[(i*imageData.height + j) * 4];
  9866. var b = imageData.data[(i*imageData.height + j) * 4 + 1];
  9867. var c = imageData.data[(i*imageData.height + j) * 4 + 2];
  9868. var height = (a + b + c) / 4 / 255 * scale.z;
  9869. if(scale.x < 0){
  9870. row.push(height);
  9871. } else {
  9872. row.unshift(height);
  9873. }
  9874. }
  9875. if(scale.y < 0){
  9876. matrix.unshift(row);
  9877. } else {
  9878. matrix.push(row);
  9879. }
  9880. }
  9881. this.updateMaxValue();
  9882. this.updateMinValue();
  9883. this.update();
  9884. };
  9885. },{"../math/Vec3":46,"../utils/Utils":69,"./ConvexPolyhedron":54,"./Shape":59}],57:[function(require,module,exports){
  9886. module.exports = Particle;
  9887. var Shape = require('./Shape');
  9888. var Vec3 = require('../math/Vec3');
  9889. /**
  9890. * Particle shape.
  9891. * @class Particle
  9892. * @constructor
  9893. * @author schteppe
  9894. * @extends Shape
  9895. */
  9896. function Particle(){
  9897. Shape.call(this);
  9898. this.type = Shape.types.PARTICLE;
  9899. }
  9900. Particle.prototype = new Shape();
  9901. Particle.prototype.constructor = Particle;
  9902. /**
  9903. * @method calculateLocalInertia
  9904. * @param {Number} mass
  9905. * @param {Vec3} target
  9906. * @return {Vec3}
  9907. */
  9908. Particle.prototype.calculateLocalInertia = function(mass,target){
  9909. target = target || new Vec3();
  9910. target.set(0, 0, 0);
  9911. return target;
  9912. };
  9913. Particle.prototype.volume = function(){
  9914. return 0;
  9915. };
  9916. Particle.prototype.updateBoundingSphereRadius = function(){
  9917. this.boundingSphereRadius = 0;
  9918. };
  9919. Particle.prototype.calculateWorldAABB = function(pos,quat,min,max){
  9920. // Get each axis max
  9921. min.copy(pos);
  9922. max.copy(pos);
  9923. };
  9924. },{"../math/Vec3":46,"./Shape":59}],58:[function(require,module,exports){
  9925. module.exports = Plane;
  9926. var Shape = require('./Shape');
  9927. var Vec3 = require('../math/Vec3');
  9928. /**
  9929. * A plane, facing in the Z direction. The plane has its surface at z=0 and everything below z=0 is assumed to be solid plane. To make the plane face in some other direction than z, you must put it inside a RigidBody and rotate that body. See the demos.
  9930. * @class Plane
  9931. * @constructor
  9932. * @extends Shape
  9933. * @author schteppe
  9934. */
  9935. function Plane(){
  9936. Shape.call(this);
  9937. this.type = Shape.types.PLANE;
  9938. // World oriented normal
  9939. this.worldNormal = new Vec3();
  9940. this.worldNormalNeedsUpdate = true;
  9941. this.boundingSphereRadius = Number.MAX_VALUE;
  9942. }
  9943. Plane.prototype = new Shape();
  9944. Plane.prototype.constructor = Plane;
  9945. Plane.prototype.computeWorldNormal = function(quat){
  9946. var n = this.worldNormal;
  9947. n.set(0,0,1);
  9948. quat.vmult(n,n);
  9949. this.worldNormalNeedsUpdate = false;
  9950. };
  9951. Plane.prototype.calculateLocalInertia = function(mass,target){
  9952. target = target || new Vec3();
  9953. return target;
  9954. };
  9955. Plane.prototype.volume = function(){
  9956. return Number.MAX_VALUE; // The plane is infinite...
  9957. };
  9958. var tempNormal = new Vec3();
  9959. Plane.prototype.calculateWorldAABB = function(pos, quat, min, max){
  9960. // The plane AABB is infinite, except if the normal is pointing along any axis
  9961. tempNormal.set(0,0,1); // Default plane normal is z
  9962. quat.vmult(tempNormal,tempNormal);
  9963. var maxVal = Number.MAX_VALUE;
  9964. min.set(-maxVal, -maxVal, -maxVal);
  9965. max.set(maxVal, maxVal, maxVal);
  9966. if(tempNormal.x === 1){ max.x = pos.x; }
  9967. if(tempNormal.y === 1){ max.y = pos.y; }
  9968. if(tempNormal.z === 1){ max.z = pos.z; }
  9969. if(tempNormal.x === -1){ min.x = pos.x; }
  9970. if(tempNormal.y === -1){ min.y = pos.y; }
  9971. if(tempNormal.z === -1){ min.z = pos.z; }
  9972. };
  9973. Plane.prototype.updateBoundingSphereRadius = function(){
  9974. this.boundingSphereRadius = Number.MAX_VALUE;
  9975. };
  9976. },{"../math/Vec3":46,"./Shape":59}],59:[function(require,module,exports){
  9977. module.exports = Shape;
  9978. var Shape = require('./Shape');
  9979. var Vec3 = require('../math/Vec3');
  9980. var Quaternion = require('../math/Quaternion');
  9981. var Material = require('../material/Material');
  9982. /**
  9983. * Base class for shapes
  9984. * @class Shape
  9985. * @constructor
  9986. * @author schteppe
  9987. * @todo Should have a mechanism for caching bounding sphere radius instead of calculating it each time
  9988. */
  9989. function Shape(){
  9990. /**
  9991. * Identifyer of the Shape.
  9992. * @property {number} id
  9993. */
  9994. this.id = Shape.idCounter++;
  9995. /**
  9996. * The type of this shape. Must be set to an int > 0 by subclasses.
  9997. * @property type
  9998. * @type {Number}
  9999. * @see Shape.types
  10000. */
  10001. this.type = 0;
  10002. /**
  10003. * The local bounding sphere radius of this shape.
  10004. * @property {Number} boundingSphereRadius
  10005. */
  10006. this.boundingSphereRadius = 0;
  10007. /**
  10008. * Whether to produce contact forces when in contact with other bodies. Note that contacts will be generated, but they will be disabled.
  10009. * @property {boolean} collisionResponse
  10010. */
  10011. this.collisionResponse = true;
  10012. /**
  10013. * @property {Material} material
  10014. */
  10015. this.material = null;
  10016. /**
  10017. * @property {Body} body
  10018. */
  10019. this.body = null;
  10020. }
  10021. Shape.prototype.constructor = Shape;
  10022. /**
  10023. * Computes the bounding sphere radius. The result is stored in the property .boundingSphereRadius
  10024. * @method updateBoundingSphereRadius
  10025. */
  10026. Shape.prototype.updateBoundingSphereRadius = function(){
  10027. throw "computeBoundingSphereRadius() not implemented for shape type "+this.type;
  10028. };
  10029. /**
  10030. * Get the volume of this shape
  10031. * @method volume
  10032. * @return {Number}
  10033. */
  10034. Shape.prototype.volume = function(){
  10035. throw "volume() not implemented for shape type "+this.type;
  10036. };
  10037. /**
  10038. * Calculates the inertia in the local frame for this shape.
  10039. * @method calculateLocalInertia
  10040. * @param {Number} mass
  10041. * @param {Vec3} target
  10042. * @see http://en.wikipedia.org/wiki/List_of_moments_of_inertia
  10043. */
  10044. Shape.prototype.calculateLocalInertia = function(mass,target){
  10045. throw "calculateLocalInertia() not implemented for shape type "+this.type;
  10046. };
  10047. Shape.idCounter = 0;
  10048. /**
  10049. * The available shape types.
  10050. * @static
  10051. * @property types
  10052. * @type {Object}
  10053. */
  10054. Shape.types = {
  10055. SPHERE:1,
  10056. PLANE:2,
  10057. BOX:4,
  10058. COMPOUND:8,
  10059. CONVEXPOLYHEDRON:16,
  10060. HEIGHTFIELD:32,
  10061. PARTICLE:64,
  10062. CYLINDER:128,
  10063. TRIMESH:256
  10064. };
  10065. },{"../material/Material":41,"../math/Quaternion":44,"../math/Vec3":46,"./Shape":59}],60:[function(require,module,exports){
  10066. module.exports = Sphere;
  10067. var Shape = require('./Shape');
  10068. var Vec3 = require('../math/Vec3');
  10069. /**
  10070. * Spherical shape
  10071. * @class Sphere
  10072. * @constructor
  10073. * @extends Shape
  10074. * @param {Number} radius The radius of the sphere, a non-negative number.
  10075. * @author schteppe / http://github.com/schteppe
  10076. */
  10077. function Sphere(radius){
  10078. Shape.call(this);
  10079. /**
  10080. * @property {Number} radius
  10081. */
  10082. this.radius = radius!==undefined ? Number(radius) : 1.0;
  10083. this.type = Shape.types.SPHERE;
  10084. if(this.radius < 0){
  10085. throw new Error('The sphere radius cannot be negative.');
  10086. }
  10087. this.updateBoundingSphereRadius();
  10088. }
  10089. Sphere.prototype = new Shape();
  10090. Sphere.prototype.constructor = Sphere;
  10091. Sphere.prototype.calculateLocalInertia = function(mass,target){
  10092. target = target || new Vec3();
  10093. var I = 2.0*mass*this.radius*this.radius/5.0;
  10094. target.x = I;
  10095. target.y = I;
  10096. target.z = I;
  10097. return target;
  10098. };
  10099. Sphere.prototype.volume = function(){
  10100. return 4.0 * Math.PI * this.radius / 3.0;
  10101. };
  10102. Sphere.prototype.updateBoundingSphereRadius = function(){
  10103. this.boundingSphereRadius = this.radius;
  10104. };
  10105. Sphere.prototype.calculateWorldAABB = function(pos,quat,min,max){
  10106. var r = this.radius;
  10107. var axes = ['x','y','z'];
  10108. for(var i=0; i<axes.length; i++){
  10109. var ax = axes[i];
  10110. min[ax] = pos[ax] - r;
  10111. max[ax] = pos[ax] + r;
  10112. }
  10113. };
  10114. },{"../math/Vec3":46,"./Shape":59}],61:[function(require,module,exports){
  10115. module.exports = Trimesh;
  10116. var Shape = require('./Shape');
  10117. var Vec3 = require('../math/Vec3');
  10118. var Quaternion = require('../math/Quaternion');
  10119. var Transform = require('../math/Transform');
  10120. var AABB = require('../collision/AABB');
  10121. var Octree = require('../utils/Octree');
  10122. /**
  10123. * @class Trimesh
  10124. * @constructor
  10125. * @param {array} vertices
  10126. * @param {array} indices
  10127. * @extends Shape
  10128. * @example
  10129. * // How to make a mesh with a single triangle
  10130. * var vertices = [
  10131. * 0, 0, 0, // vertex 0
  10132. * 1, 0, 0, // vertex 1
  10133. * 0, 1, 0 // vertex 2
  10134. * ];
  10135. * var indices = [
  10136. * 0, 1, 2 // triangle 0
  10137. * ];
  10138. * var trimeshShape = new Trimesh(vertices, indices);
  10139. */
  10140. function Trimesh(vertices, indices) {
  10141. Shape.call(this);
  10142. this.type = Shape.types.TRIMESH;
  10143. /**
  10144. * @property vertices
  10145. * @type {Array}
  10146. */
  10147. this.vertices = new Float32Array(vertices);
  10148. /**
  10149. * Array of integers, indicating which vertices each triangle consists of. The length of this array is thus 3 times the number of triangles.
  10150. * @property indices
  10151. * @type {Array}
  10152. */
  10153. this.indices = new Int16Array(indices);
  10154. /**
  10155. * The normals data.
  10156. * @property normals
  10157. * @type {Array}
  10158. */
  10159. this.normals = new Float32Array(indices.length);
  10160. /**
  10161. * The local AABB of the mesh.
  10162. * @property aabb
  10163. * @type {Array}
  10164. */
  10165. this.aabb = new AABB();
  10166. /**
  10167. * References to vertex pairs, making up all unique edges in the trimesh.
  10168. * @property {array} edges
  10169. */
  10170. this.edges = null;
  10171. /**
  10172. * Local scaling of the mesh. Use .setScale() to set it.
  10173. * @property {Vec3} scale
  10174. */
  10175. this.scale = new Vec3(1, 1, 1);
  10176. /**
  10177. * The indexed triangles. Use .updateTree() to update it.
  10178. * @property {Octree} tree
  10179. */
  10180. this.tree = new Octree();
  10181. this.updateEdges();
  10182. this.updateNormals();
  10183. this.updateAABB();
  10184. this.updateBoundingSphereRadius();
  10185. this.updateTree();
  10186. }
  10187. Trimesh.prototype = new Shape();
  10188. Trimesh.prototype.constructor = Trimesh;
  10189. var computeNormals_n = new Vec3();
  10190. /**
  10191. * @method updateTree
  10192. */
  10193. Trimesh.prototype.updateTree = function(){
  10194. var tree = this.tree;
  10195. tree.reset();
  10196. tree.aabb.copy(this.aabb);
  10197. var scale = this.scale; // The local mesh AABB is scaled, but the octree AABB should be unscaled
  10198. tree.aabb.lowerBound.x *= 1 / scale.x;
  10199. tree.aabb.lowerBound.y *= 1 / scale.y;
  10200. tree.aabb.lowerBound.z *= 1 / scale.z;
  10201. tree.aabb.upperBound.x *= 1 / scale.x;
  10202. tree.aabb.upperBound.y *= 1 / scale.y;
  10203. tree.aabb.upperBound.z *= 1 / scale.z;
  10204. // Insert all triangles
  10205. var triangleAABB = new AABB();
  10206. var a = new Vec3();
  10207. var b = new Vec3();
  10208. var c = new Vec3();
  10209. var points = [a, b, c];
  10210. for (var i = 0; i < this.indices.length / 3; i++) {
  10211. //this.getTriangleVertices(i, a, b, c);
  10212. // Get unscaled triangle verts
  10213. var i3 = i * 3;
  10214. this._getUnscaledVertex(this.indices[i3], a);
  10215. this._getUnscaledVertex(this.indices[i3 + 1], b);
  10216. this._getUnscaledVertex(this.indices[i3 + 2], c);
  10217. triangleAABB.setFromPoints(points);
  10218. tree.insert(triangleAABB, i);
  10219. }
  10220. tree.removeEmptyNodes();
  10221. };
  10222. var unscaledAABB = new AABB();
  10223. /**
  10224. * Get triangles in a local AABB from the trimesh.
  10225. * @method getTrianglesInAABB
  10226. * @param {AABB} aabb
  10227. * @param {array} result An array of integers, referencing the queried triangles.
  10228. */
  10229. Trimesh.prototype.getTrianglesInAABB = function(aabb, result){
  10230. unscaledAABB.copy(aabb);
  10231. // Scale it to local
  10232. var scale = this.scale;
  10233. var isx = scale.x;
  10234. var isy = scale.y;
  10235. var isz = scale.z;
  10236. var l = unscaledAABB.lowerBound;
  10237. var u = unscaledAABB.upperBound;
  10238. l.x /= isx;
  10239. l.y /= isy;
  10240. l.z /= isz;
  10241. u.x /= isx;
  10242. u.y /= isy;
  10243. u.z /= isz;
  10244. return this.tree.aabbQuery(unscaledAABB, result);
  10245. };
  10246. /**
  10247. * @method setScale
  10248. * @param {Vec3} scale
  10249. */
  10250. Trimesh.prototype.setScale = function(scale){
  10251. var wasUniform = this.scale.x === this.scale.y === this.scale.z;
  10252. var isUniform = scale.x === scale.y === scale.z;
  10253. if(!(wasUniform && isUniform)){
  10254. // Non-uniform scaling. Need to update normals.
  10255. this.updateNormals();
  10256. }
  10257. this.scale.copy(scale);
  10258. this.updateAABB();
  10259. this.updateBoundingSphereRadius();
  10260. };
  10261. /**
  10262. * Compute the normals of the faces. Will save in the .normals array.
  10263. * @method updateNormals
  10264. */
  10265. Trimesh.prototype.updateNormals = function(){
  10266. var n = computeNormals_n;
  10267. // Generate normals
  10268. var normals = this.normals;
  10269. for(var i=0; i < this.indices.length / 3; i++){
  10270. var i3 = i * 3;
  10271. var a = this.indices[i3],
  10272. b = this.indices[i3 + 1],
  10273. c = this.indices[i3 + 2];
  10274. this.getVertex(a, va);
  10275. this.getVertex(b, vb);
  10276. this.getVertex(c, vc);
  10277. Trimesh.computeNormal(vb, va, vc, n);
  10278. normals[i3] = n.x;
  10279. normals[i3 + 1] = n.y;
  10280. normals[i3 + 2] = n.z;
  10281. }
  10282. };
  10283. /**
  10284. * Update the .edges property
  10285. * @method updateEdges
  10286. */
  10287. Trimesh.prototype.updateEdges = function(){
  10288. var edges = {};
  10289. var add = function(indexA, indexB){
  10290. var key = a < b ? a + '_' + b : b + '_' + a;
  10291. edges[key] = true;
  10292. };
  10293. for(var i=0; i < this.indices.length / 3; i++){
  10294. var i3 = i * 3;
  10295. var a = this.indices[i3],
  10296. b = this.indices[i3 + 1],
  10297. c = this.indices[i3 + 2];
  10298. add(a,b);
  10299. add(b,c);
  10300. add(c,a);
  10301. }
  10302. var keys = Object.keys(edges);
  10303. this.edges = new Int16Array(keys.length * 2);
  10304. for (var i = 0; i < keys.length; i++) {
  10305. var indices = keys[i].split('_');
  10306. this.edges[2 * i] = parseInt(indices[0], 10);
  10307. this.edges[2 * i + 1] = parseInt(indices[1], 10);
  10308. }
  10309. };
  10310. /**
  10311. * Get an edge vertex
  10312. * @method getEdgeVertex
  10313. * @param {number} edgeIndex
  10314. * @param {number} firstOrSecond 0 or 1, depending on which one of the vertices you need.
  10315. * @param {Vec3} vertexStore Where to store the result
  10316. */
  10317. Trimesh.prototype.getEdgeVertex = function(edgeIndex, firstOrSecond, vertexStore){
  10318. var vertexIndex = this.edges[edgeIndex * 2 + (firstOrSecond ? 1 : 0)];
  10319. this.getVertex(vertexIndex, vertexStore);
  10320. };
  10321. var getEdgeVector_va = new Vec3();
  10322. var getEdgeVector_vb = new Vec3();
  10323. /**
  10324. * Get a vector along an edge.
  10325. * @method getEdgeVector
  10326. * @param {number} edgeIndex
  10327. * @param {Vec3} vectorStore
  10328. */
  10329. Trimesh.prototype.getEdgeVector = function(edgeIndex, vectorStore){
  10330. var va = getEdgeVector_va;
  10331. var vb = getEdgeVector_vb;
  10332. this.getEdgeVertex(edgeIndex, 0, va);
  10333. this.getEdgeVertex(edgeIndex, 1, vb);
  10334. vb.vsub(va, vectorStore);
  10335. };
  10336. /**
  10337. * Get face normal given 3 vertices
  10338. * @static
  10339. * @method computeNormal
  10340. * @param {Vec3} va
  10341. * @param {Vec3} vb
  10342. * @param {Vec3} vc
  10343. * @param {Vec3} target
  10344. */
  10345. var cb = new Vec3();
  10346. var ab = new Vec3();
  10347. Trimesh.computeNormal = function ( va, vb, vc, target ) {
  10348. vb.vsub(va,ab);
  10349. vc.vsub(vb,cb);
  10350. cb.cross(ab,target);
  10351. if ( !target.isZero() ) {
  10352. target.normalize();
  10353. }
  10354. };
  10355. var va = new Vec3();
  10356. var vb = new Vec3();
  10357. var vc = new Vec3();
  10358. /**
  10359. * Get vertex i.
  10360. * @method getVertex
  10361. * @param {number} i
  10362. * @param {Vec3} out
  10363. * @return {Vec3} The "out" vector object
  10364. */
  10365. Trimesh.prototype.getVertex = function(i, out){
  10366. var scale = this.scale;
  10367. this._getUnscaledVertex(i, out);
  10368. out.x *= scale.x;
  10369. out.y *= scale.y;
  10370. out.z *= scale.z;
  10371. return out;
  10372. };
  10373. /**
  10374. * Get raw vertex i
  10375. * @private
  10376. * @method _getUnscaledVertex
  10377. * @param {number} i
  10378. * @param {Vec3} out
  10379. * @return {Vec3} The "out" vector object
  10380. */
  10381. Trimesh.prototype._getUnscaledVertex = function(i, out){
  10382. var i3 = i * 3;
  10383. var vertices = this.vertices;
  10384. return out.set(
  10385. vertices[i3],
  10386. vertices[i3 + 1],
  10387. vertices[i3 + 2]
  10388. );
  10389. };
  10390. /**
  10391. * Get a vertex from the trimesh,transformed by the given position and quaternion.
  10392. * @method getWorldVertex
  10393. * @param {number} i
  10394. * @param {Vec3} pos
  10395. * @param {Quaternion} quat
  10396. * @param {Vec3} out
  10397. * @return {Vec3} The "out" vector object
  10398. */
  10399. Trimesh.prototype.getWorldVertex = function(i, pos, quat, out){
  10400. this.getVertex(i, out);
  10401. Transform.pointToWorldFrame(pos, quat, out, out);
  10402. return out;
  10403. };
  10404. /**
  10405. * Get the three vertices for triangle i.
  10406. * @method getTriangleVertices
  10407. * @param {number} i
  10408. * @param {Vec3} a
  10409. * @param {Vec3} b
  10410. * @param {Vec3} c
  10411. */
  10412. Trimesh.prototype.getTriangleVertices = function(i, a, b, c){
  10413. var i3 = i * 3;
  10414. this.getVertex(this.indices[i3], a);
  10415. this.getVertex(this.indices[i3 + 1], b);
  10416. this.getVertex(this.indices[i3 + 2], c);
  10417. };
  10418. /**
  10419. * Compute the normal of triangle i.
  10420. * @method getNormal
  10421. * @param {Number} i
  10422. * @param {Vec3} target
  10423. * @return {Vec3} The "target" vector object
  10424. */
  10425. Trimesh.prototype.getNormal = function(i, target){
  10426. var i3 = i * 3;
  10427. return target.set(
  10428. this.normals[i3],
  10429. this.normals[i3 + 1],
  10430. this.normals[i3 + 2]
  10431. );
  10432. };
  10433. var cli_aabb = new AABB();
  10434. /**
  10435. * @method calculateLocalInertia
  10436. * @param {Number} mass
  10437. * @param {Vec3} target
  10438. * @return {Vec3} The "target" vector object
  10439. */
  10440. Trimesh.prototype.calculateLocalInertia = function(mass,target){
  10441. // Approximate with box inertia
  10442. // Exact inertia calculation is overkill, but see http://geometrictools.com/Documentation/PolyhedralMassProperties.pdf for the correct way to do it
  10443. this.computeLocalAABB(cli_aabb);
  10444. var x = cli_aabb.upperBound.x - cli_aabb.lowerBound.x,
  10445. y = cli_aabb.upperBound.y - cli_aabb.lowerBound.y,
  10446. z = cli_aabb.upperBound.z - cli_aabb.lowerBound.z;
  10447. return target.set(
  10448. 1.0 / 12.0 * mass * ( 2*y*2*y + 2*z*2*z ),
  10449. 1.0 / 12.0 * mass * ( 2*x*2*x + 2*z*2*z ),
  10450. 1.0 / 12.0 * mass * ( 2*y*2*y + 2*x*2*x )
  10451. );
  10452. };
  10453. var computeLocalAABB_worldVert = new Vec3();
  10454. /**
  10455. * Compute the local AABB for the trimesh
  10456. * @method computeLocalAABB
  10457. * @param {AABB} aabb
  10458. */
  10459. Trimesh.prototype.computeLocalAABB = function(aabb){
  10460. var l = aabb.lowerBound,
  10461. u = aabb.upperBound,
  10462. n = this.vertices.length,
  10463. vertices = this.vertices,
  10464. v = computeLocalAABB_worldVert;
  10465. this.getVertex(0, v);
  10466. l.copy(v);
  10467. u.copy(v);
  10468. for(var i=0; i !== n; i++){
  10469. this.getVertex(i, v);
  10470. if(v.x < l.x){
  10471. l.x = v.x;
  10472. } else if(v.x > u.x){
  10473. u.x = v.x;
  10474. }
  10475. if(v.y < l.y){
  10476. l.y = v.y;
  10477. } else if(v.y > u.y){
  10478. u.y = v.y;
  10479. }
  10480. if(v.z < l.z){
  10481. l.z = v.z;
  10482. } else if(v.z > u.z){
  10483. u.z = v.z;
  10484. }
  10485. }
  10486. };
  10487. /**
  10488. * Update the .aabb property
  10489. * @method updateAABB
  10490. */
  10491. Trimesh.prototype.updateAABB = function(){
  10492. this.computeLocalAABB(this.aabb);
  10493. };
  10494. /**
  10495. * Will update the .boundingSphereRadius property
  10496. * @method updateBoundingSphereRadius
  10497. */
  10498. Trimesh.prototype.updateBoundingSphereRadius = function(){
  10499. // Assume points are distributed with local (0,0,0) as center
  10500. var max2 = 0;
  10501. var vertices = this.vertices;
  10502. var v = new Vec3();
  10503. for(var i=0, N=vertices.length / 3; i !== N; i++) {
  10504. this.getVertex(i, v);
  10505. var norm2 = v.norm2();
  10506. if(norm2 > max2){
  10507. max2 = norm2;
  10508. }
  10509. }
  10510. this.boundingSphereRadius = Math.sqrt(max2);
  10511. };
  10512. var tempWorldVertex = new Vec3();
  10513. var calculateWorldAABB_frame = new Transform();
  10514. var calculateWorldAABB_aabb = new AABB();
  10515. /**
  10516. * @method calculateWorldAABB
  10517. * @param {Vec3} pos
  10518. * @param {Quaternion} quat
  10519. * @param {Vec3} min
  10520. * @param {Vec3} max
  10521. */
  10522. Trimesh.prototype.calculateWorldAABB = function(pos,quat,min,max){
  10523. /*
  10524. var n = this.vertices.length / 3,
  10525. verts = this.vertices;
  10526. var minx,miny,minz,maxx,maxy,maxz;
  10527. var v = tempWorldVertex;
  10528. for(var i=0; i<n; i++){
  10529. this.getVertex(i, v);
  10530. quat.vmult(v, v);
  10531. pos.vadd(v, v);
  10532. if (v.x < minx || minx===undefined){
  10533. minx = v.x;
  10534. } else if(v.x > maxx || maxx===undefined){
  10535. maxx = v.x;
  10536. }
  10537. if (v.y < miny || miny===undefined){
  10538. miny = v.y;
  10539. } else if(v.y > maxy || maxy===undefined){
  10540. maxy = v.y;
  10541. }
  10542. if (v.z < minz || minz===undefined){
  10543. minz = v.z;
  10544. } else if(v.z > maxz || maxz===undefined){
  10545. maxz = v.z;
  10546. }
  10547. }
  10548. min.set(minx,miny,minz);
  10549. max.set(maxx,maxy,maxz);
  10550. */
  10551. // Faster approximation using local AABB
  10552. var frame = calculateWorldAABB_frame;
  10553. var result = calculateWorldAABB_aabb;
  10554. frame.position = pos;
  10555. frame.quaternion = quat;
  10556. this.aabb.toWorldFrame(frame, result);
  10557. min.copy(result.lowerBound);
  10558. max.copy(result.upperBound);
  10559. };
  10560. /**
  10561. * Get approximate volume
  10562. * @method volume
  10563. * @return {Number}
  10564. */
  10565. Trimesh.prototype.volume = function(){
  10566. return 4.0 * Math.PI * this.boundingSphereRadius / 3.0;
  10567. };
  10568. /**
  10569. * Create a Trimesh instance, shaped as a torus.
  10570. * @static
  10571. * @method createTorus
  10572. * @param {number} [radius=1]
  10573. * @param {number} [tube=0.5]
  10574. * @param {number} [radialSegments=8]
  10575. * @param {number} [tubularSegments=6]
  10576. * @param {number} [arc=6.283185307179586]
  10577. * @return {Trimesh} A torus
  10578. */
  10579. Trimesh.createTorus = function (radius, tube, radialSegments, tubularSegments, arc) {
  10580. radius = radius || 1;
  10581. tube = tube || 0.5;
  10582. radialSegments = radialSegments || 8;
  10583. tubularSegments = tubularSegments || 6;
  10584. arc = arc || Math.PI * 2;
  10585. var vertices = [];
  10586. var indices = [];
  10587. for ( var j = 0; j <= radialSegments; j ++ ) {
  10588. for ( var i = 0; i <= tubularSegments; i ++ ) {
  10589. var u = i / tubularSegments * arc;
  10590. var v = j / radialSegments * Math.PI * 2;
  10591. var x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
  10592. var y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
  10593. var z = tube * Math.sin( v );
  10594. vertices.push( x, y, z );
  10595. }
  10596. }
  10597. for ( var j = 1; j <= radialSegments; j ++ ) {
  10598. for ( var i = 1; i <= tubularSegments; i ++ ) {
  10599. var a = ( tubularSegments + 1 ) * j + i - 1;
  10600. var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
  10601. var c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
  10602. var d = ( tubularSegments + 1 ) * j + i;
  10603. indices.push(a, b, d);
  10604. indices.push(b, c, d);
  10605. }
  10606. }
  10607. return new Trimesh(vertices, indices);
  10608. };
  10609. },{"../collision/AABB":18,"../math/Quaternion":44,"../math/Transform":45,"../math/Vec3":46,"../utils/Octree":66,"./Shape":59}],62:[function(require,module,exports){
  10610. module.exports = GSSolver;
  10611. var Vec3 = require('../math/Vec3');
  10612. var Quaternion = require('../math/Quaternion');
  10613. var Solver = require('./Solver');
  10614. /**
  10615. * Constraint equation Gauss-Seidel solver.
  10616. * @class GSSolver
  10617. * @constructor
  10618. * @todo The spook parameters should be specified for each constraint, not globally.
  10619. * @author schteppe / https://github.com/schteppe
  10620. * @see https://www8.cs.umu.se/kurser/5DV058/VT09/lectures/spooknotes.pdf
  10621. * @extends Solver
  10622. */
  10623. function GSSolver(){
  10624. Solver.call(this);
  10625. /**
  10626. * The number of solver iterations determines quality of the constraints in the world. The more iterations, the more correct simulation. More iterations need more computations though. If you have a large gravity force in your world, you will need more iterations.
  10627. * @property iterations
  10628. * @type {Number}
  10629. * @todo write more about solver and iterations in the wiki
  10630. */
  10631. this.iterations = 10;
  10632. /**
  10633. * When tolerance is reached, the system is assumed to be converged.
  10634. * @property tolerance
  10635. * @type {Number}
  10636. */
  10637. this.tolerance = 1e-7;
  10638. }
  10639. GSSolver.prototype = new Solver();
  10640. var GSSolver_solve_lambda = []; // Just temporary number holders that we want to reuse each solve.
  10641. var GSSolver_solve_invCs = [];
  10642. var GSSolver_solve_Bs = [];
  10643. GSSolver.prototype.solve = function(dt,world){
  10644. var iter = 0,
  10645. maxIter = this.iterations,
  10646. tolSquared = this.tolerance*this.tolerance,
  10647. equations = this.equations,
  10648. Neq = equations.length,
  10649. bodies = world.bodies,
  10650. Nbodies = bodies.length,
  10651. h = dt,
  10652. q, B, invC, deltalambda, deltalambdaTot, GWlambda, lambdaj;
  10653. // Update solve mass
  10654. if(Neq !== 0){
  10655. for(var i=0; i!==Nbodies; i++){
  10656. bodies[i].updateSolveMassProperties();
  10657. }
  10658. }
  10659. // Things that does not change during iteration can be computed once
  10660. var invCs = GSSolver_solve_invCs,
  10661. Bs = GSSolver_solve_Bs,
  10662. lambda = GSSolver_solve_lambda;
  10663. invCs.length = Neq;
  10664. Bs.length = Neq;
  10665. lambda.length = Neq;
  10666. for(var i=0; i!==Neq; i++){
  10667. var c = equations[i];
  10668. lambda[i] = 0.0;
  10669. Bs[i] = c.computeB(h);
  10670. invCs[i] = 1.0 / c.computeC();
  10671. }
  10672. if(Neq !== 0){
  10673. // Reset vlambda
  10674. for(var i=0; i!==Nbodies; i++){
  10675. var b=bodies[i],
  10676. vlambda=b.vlambda,
  10677. wlambda=b.wlambda;
  10678. vlambda.set(0,0,0);
  10679. wlambda.set(0,0,0);
  10680. }
  10681. // Iterate over equations
  10682. for(iter=0; iter!==maxIter; iter++){
  10683. // Accumulate the total error for each iteration.
  10684. deltalambdaTot = 0.0;
  10685. for(var j=0; j!==Neq; j++){
  10686. var c = equations[j];
  10687. // Compute iteration
  10688. B = Bs[j];
  10689. invC = invCs[j];
  10690. lambdaj = lambda[j];
  10691. GWlambda = c.computeGWlambda();
  10692. deltalambda = invC * ( B - GWlambda - c.eps * lambdaj );
  10693. // Clamp if we are not within the min/max interval
  10694. if(lambdaj + deltalambda < c.minForce){
  10695. deltalambda = c.minForce - lambdaj;
  10696. } else if(lambdaj + deltalambda > c.maxForce){
  10697. deltalambda = c.maxForce - lambdaj;
  10698. }
  10699. lambda[j] += deltalambda;
  10700. deltalambdaTot += deltalambda > 0.0 ? deltalambda : -deltalambda; // abs(deltalambda)
  10701. c.addToWlambda(deltalambda);
  10702. }
  10703. // If the total error is small enough - stop iterate
  10704. if(deltalambdaTot*deltalambdaTot < tolSquared){
  10705. break;
  10706. }
  10707. }
  10708. // Add result to velocity
  10709. for(var i=0; i!==Nbodies; i++){
  10710. var b=bodies[i],
  10711. v=b.velocity,
  10712. w=b.angularVelocity;
  10713. b.vlambda.vmul(b.linearFactor, b.vlambda);
  10714. v.vadd(b.vlambda, v);
  10715. b.wlambda.vmul(b.angularFactor, b.wlambda);
  10716. w.vadd(b.wlambda, w);
  10717. }
  10718. // Set the .multiplier property of each equation
  10719. var l = equations.length;
  10720. var invDt = 1 / h;
  10721. while(l--){
  10722. equations[l].multiplier = lambda[l] * invDt;
  10723. }
  10724. }
  10725. return iter;
  10726. };
  10727. },{"../math/Quaternion":44,"../math/Vec3":46,"./Solver":63}],63:[function(require,module,exports){
  10728. module.exports = Solver;
  10729. /**
  10730. * Constraint equation solver base class.
  10731. * @class Solver
  10732. * @constructor
  10733. * @author schteppe / https://github.com/schteppe
  10734. */
  10735. function Solver(){
  10736. /**
  10737. * All equations to be solved
  10738. * @property {Array} equations
  10739. */
  10740. this.equations = [];
  10741. }
  10742. /**
  10743. * Should be implemented in subclasses!
  10744. * @method solve
  10745. * @param {Number} dt
  10746. * @param {World} world
  10747. */
  10748. Solver.prototype.solve = function(dt,world){
  10749. // Should return the number of iterations done!
  10750. return 0;
  10751. };
  10752. /**
  10753. * Add an equation
  10754. * @method addEquation
  10755. * @param {Equation} eq
  10756. */
  10757. Solver.prototype.addEquation = function(eq){
  10758. if (eq.enabled) {
  10759. this.equations.push(eq);
  10760. }
  10761. };
  10762. /**
  10763. * Remove an equation
  10764. * @method removeEquation
  10765. * @param {Equation} eq
  10766. */
  10767. Solver.prototype.removeEquation = function(eq){
  10768. var eqs = this.equations;
  10769. var i = eqs.indexOf(eq);
  10770. if(i !== -1){
  10771. eqs.splice(i,1);
  10772. }
  10773. };
  10774. /**
  10775. * Add all equations
  10776. * @method removeAllEquations
  10777. */
  10778. Solver.prototype.removeAllEquations = function(){
  10779. this.equations.length = 0;
  10780. };
  10781. },{}],64:[function(require,module,exports){
  10782. module.exports = SplitSolver;
  10783. var Vec3 = require('../math/Vec3');
  10784. var Quaternion = require('../math/Quaternion');
  10785. var Solver = require('./Solver');
  10786. var Body = require('../objects/Body');
  10787. /**
  10788. * Splits the equations into islands and solves them independently. Can improve performance.
  10789. * @class SplitSolver
  10790. * @constructor
  10791. * @extends Solver
  10792. * @param {Solver} subsolver
  10793. */
  10794. function SplitSolver(subsolver){
  10795. Solver.call(this);
  10796. this.iterations = 10;
  10797. this.tolerance = 1e-7;
  10798. this.subsolver = subsolver;
  10799. this.nodes = [];
  10800. this.nodePool = [];
  10801. // Create needed nodes, reuse if possible
  10802. while(this.nodePool.length < 128){
  10803. this.nodePool.push(this.createNode());
  10804. }
  10805. }
  10806. SplitSolver.prototype = new Solver();
  10807. // Returns the number of subsystems
  10808. var SplitSolver_solve_nodes = []; // All allocated node objects
  10809. var SplitSolver_solve_nodePool = []; // All allocated node objects
  10810. var SplitSolver_solve_eqs = []; // Temp array
  10811. var SplitSolver_solve_bds = []; // Temp array
  10812. var SplitSolver_solve_dummyWorld = {bodies:[]}; // Temp object
  10813. var STATIC = Body.STATIC;
  10814. function getUnvisitedNode(nodes){
  10815. var Nnodes = nodes.length;
  10816. for(var i=0; i!==Nnodes; i++){
  10817. var node = nodes[i];
  10818. if(!node.visited && !(node.body.type & STATIC)){
  10819. return node;
  10820. }
  10821. }
  10822. return false;
  10823. }
  10824. var queue = [];
  10825. function bfs(root,visitFunc,bds,eqs){
  10826. queue.push(root);
  10827. root.visited = true;
  10828. visitFunc(root,bds,eqs);
  10829. while(queue.length) {
  10830. var node = queue.pop();
  10831. // Loop over unvisited child nodes
  10832. var child;
  10833. while((child = getUnvisitedNode(node.children))) {
  10834. child.visited = true;
  10835. visitFunc(child,bds,eqs);
  10836. queue.push(child);
  10837. }
  10838. }
  10839. }
  10840. function visitFunc(node,bds,eqs){
  10841. bds.push(node.body);
  10842. var Neqs = node.eqs.length;
  10843. for(var i=0; i!==Neqs; i++){
  10844. var eq = node.eqs[i];
  10845. if(eqs.indexOf(eq) === -1){
  10846. eqs.push(eq);
  10847. }
  10848. }
  10849. }
  10850. SplitSolver.prototype.createNode = function(){
  10851. return { body:null, children:[], eqs:[], visited:false };
  10852. };
  10853. /**
  10854. * Solve the subsystems
  10855. * @method solve
  10856. * @param {Number} dt
  10857. * @param {World} world
  10858. */
  10859. SplitSolver.prototype.solve = function(dt,world){
  10860. var nodes=SplitSolver_solve_nodes,
  10861. nodePool=this.nodePool,
  10862. bodies=world.bodies,
  10863. equations=this.equations,
  10864. Neq=equations.length,
  10865. Nbodies=bodies.length,
  10866. subsolver=this.subsolver;
  10867. // Create needed nodes, reuse if possible
  10868. while(nodePool.length < Nbodies){
  10869. nodePool.push(this.createNode());
  10870. }
  10871. nodes.length = Nbodies;
  10872. for (var i = 0; i < Nbodies; i++) {
  10873. nodes[i] = nodePool[i];
  10874. }
  10875. // Reset node values
  10876. for(var i=0; i!==Nbodies; i++){
  10877. var node = nodes[i];
  10878. node.body = bodies[i];
  10879. node.children.length = 0;
  10880. node.eqs.length = 0;
  10881. node.visited = false;
  10882. }
  10883. for(var k=0; k!==Neq; k++){
  10884. var eq=equations[k],
  10885. i=bodies.indexOf(eq.bi),
  10886. j=bodies.indexOf(eq.bj),
  10887. ni=nodes[i],
  10888. nj=nodes[j];
  10889. ni.children.push(nj);
  10890. ni.eqs.push(eq);
  10891. nj.children.push(ni);
  10892. nj.eqs.push(eq);
  10893. }
  10894. var child, n=0, eqs=SplitSolver_solve_eqs;
  10895. subsolver.tolerance = this.tolerance;
  10896. subsolver.iterations = this.iterations;
  10897. var dummyWorld = SplitSolver_solve_dummyWorld;
  10898. while((child = getUnvisitedNode(nodes))){
  10899. eqs.length = 0;
  10900. dummyWorld.bodies.length = 0;
  10901. bfs(child, visitFunc, dummyWorld.bodies, eqs);
  10902. var Neqs = eqs.length;
  10903. eqs = eqs.sort(sortById);
  10904. for(var i=0; i!==Neqs; i++){
  10905. subsolver.addEquation(eqs[i]);
  10906. }
  10907. var iter = subsolver.solve(dt,dummyWorld);
  10908. subsolver.removeAllEquations();
  10909. n++;
  10910. }
  10911. return n;
  10912. };
  10913. function sortById(a, b){
  10914. return b.id - a.id;
  10915. }
  10916. },{"../math/Quaternion":44,"../math/Vec3":46,"../objects/Body":47,"./Solver":63}],65:[function(require,module,exports){
  10917. /**
  10918. * Base class for objects that dispatches events.
  10919. * @class EventTarget
  10920. * @constructor
  10921. */
  10922. var EventTarget = function () {
  10923. };
  10924. module.exports = EventTarget;
  10925. EventTarget.prototype = {
  10926. constructor: EventTarget,
  10927. /**
  10928. * Add an event listener
  10929. * @method addEventListener
  10930. * @param {String} type
  10931. * @param {Function} listener
  10932. * @return {EventTarget} The self object, for chainability.
  10933. */
  10934. addEventListener: function ( type, listener ) {
  10935. if ( this._listeners === undefined ){ this._listeners = {}; }
  10936. var listeners = this._listeners;
  10937. if ( listeners[ type ] === undefined ) {
  10938. listeners[ type ] = [];
  10939. }
  10940. if ( listeners[ type ].indexOf( listener ) === - 1 ) {
  10941. listeners[ type ].push( listener );
  10942. }
  10943. return this;
  10944. },
  10945. /**
  10946. * Check if an event listener is added
  10947. * @method hasEventListener
  10948. * @param {String} type
  10949. * @param {Function} listener
  10950. * @return {Boolean}
  10951. */
  10952. hasEventListener: function ( type, listener ) {
  10953. if ( this._listeners === undefined ){ return false; }
  10954. var listeners = this._listeners;
  10955. if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) {
  10956. return true;
  10957. }
  10958. return false;
  10959. },
  10960. /**
  10961. * Check if any event listener of the given type is added
  10962. * @method hasAnyEventListener
  10963. * @param {String} type
  10964. * @return {Boolean}
  10965. */
  10966. hasAnyEventListener: function ( type ) {
  10967. if ( this._listeners === undefined ){ return false; }
  10968. var listeners = this._listeners;
  10969. return ( listeners[ type ] !== undefined );
  10970. },
  10971. /**
  10972. * Remove an event listener
  10973. * @method removeEventListener
  10974. * @param {String} type
  10975. * @param {Function} listener
  10976. * @return {EventTarget} The self object, for chainability.
  10977. */
  10978. removeEventListener: function ( type, listener ) {
  10979. if ( this._listeners === undefined ){ return this; }
  10980. var listeners = this._listeners;
  10981. if ( listeners[type] === undefined ){ return this; }
  10982. var index = listeners[ type ].indexOf( listener );
  10983. if ( index !== - 1 ) {
  10984. listeners[ type ].splice( index, 1 );
  10985. }
  10986. return this;
  10987. },
  10988. /**
  10989. * Emit an event.
  10990. * @method dispatchEvent
  10991. * @param {Object} event
  10992. * @param {String} event.type
  10993. * @return {EventTarget} The self object, for chainability.
  10994. */
  10995. dispatchEvent: function ( event ) {
  10996. if ( this._listeners === undefined ){ return this; }
  10997. var listeners = this._listeners;
  10998. var listenerArray = listeners[ event.type ];
  10999. if ( listenerArray !== undefined ) {
  11000. event.target = this;
  11001. for ( var i = 0, l = listenerArray.length; i < l; i ++ ) {
  11002. listenerArray[ i ].call( this, event );
  11003. }
  11004. }
  11005. return this;
  11006. }
  11007. };
  11008. },{}],66:[function(require,module,exports){
  11009. var AABB = require('../collision/AABB');
  11010. var Vec3 = require('../math/Vec3');
  11011. module.exports = Octree;
  11012. /**
  11013. * @class OctreeNode
  11014. * @param {object} [options]
  11015. * @param {Octree} [options.root]
  11016. * @param {AABB} [options.aabb]
  11017. */
  11018. function OctreeNode(options){
  11019. options = options || {};
  11020. /**
  11021. * The root node
  11022. * @property {OctreeNode} root
  11023. */
  11024. this.root = options.root || null;
  11025. /**
  11026. * Boundary of this node
  11027. * @property {AABB} aabb
  11028. */
  11029. this.aabb = options.aabb ? options.aabb.clone() : new AABB();
  11030. /**
  11031. * Contained data at the current node level.
  11032. * @property {Array} data
  11033. */
  11034. this.data = [];
  11035. /**
  11036. * Children to this node
  11037. * @property {Array} children
  11038. */
  11039. this.children = [];
  11040. }
  11041. /**
  11042. * @class Octree
  11043. * @param {AABB} aabb The total AABB of the tree
  11044. * @param {object} [options]
  11045. * @param {number} [options.maxDepth=8]
  11046. * @extends OctreeNode
  11047. */
  11048. function Octree(aabb, options){
  11049. options = options || {};
  11050. options.root = null;
  11051. options.aabb = aabb;
  11052. OctreeNode.call(this, options);
  11053. /**
  11054. * Maximum subdivision depth
  11055. * @property {number} maxDepth
  11056. */
  11057. this.maxDepth = typeof(options.maxDepth) !== 'undefined' ? options.maxDepth : 8;
  11058. }
  11059. Octree.prototype = new OctreeNode();
  11060. OctreeNode.prototype.reset = function(aabb, options){
  11061. this.children.length = this.data.length = 0;
  11062. };
  11063. /**
  11064. * Insert data into this node
  11065. * @method insert
  11066. * @param {AABB} aabb
  11067. * @param {object} elementData
  11068. * @return {boolean} True if successful, otherwise false
  11069. */
  11070. OctreeNode.prototype.insert = function(aabb, elementData, level){
  11071. var nodeData = this.data;
  11072. level = level || 0;
  11073. // Ignore objects that do not belong in this node
  11074. if (!this.aabb.contains(aabb)){
  11075. return false; // object cannot be added
  11076. }
  11077. var children = this.children;
  11078. if(level < (this.maxDepth || this.root.maxDepth)){
  11079. // Subdivide if there are no children yet
  11080. var subdivided = false;
  11081. if (!children.length){
  11082. this.subdivide();
  11083. subdivided = true;
  11084. }
  11085. // add to whichever node will accept it
  11086. for (var i = 0; i !== 8; i++) {
  11087. if (children[i].insert(aabb, elementData, level + 1)){
  11088. return true;
  11089. }
  11090. }
  11091. if(subdivided){
  11092. // No children accepted! Might as well just remove em since they contain none
  11093. children.length = 0;
  11094. }
  11095. }
  11096. // Too deep, or children didnt want it. add it in current node
  11097. nodeData.push(elementData);
  11098. return true;
  11099. };
  11100. var halfDiagonal = new Vec3();
  11101. /**
  11102. * Create 8 equally sized children nodes and put them in the .children array.
  11103. * @method subdivide
  11104. */
  11105. OctreeNode.prototype.subdivide = function() {
  11106. var aabb = this.aabb;
  11107. var l = aabb.lowerBound;
  11108. var u = aabb.upperBound;
  11109. var children = this.children;
  11110. children.push(
  11111. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,0,0) }) }),
  11112. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,0,0) }) }),
  11113. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,1,0) }) }),
  11114. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,1,1) }) }),
  11115. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,1,1) }) }),
  11116. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,0,1) }) }),
  11117. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,0,1) }) }),
  11118. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,1,0) }) })
  11119. );
  11120. u.vsub(l, halfDiagonal);
  11121. halfDiagonal.scale(0.5, halfDiagonal);
  11122. var root = this.root || this;
  11123. for (var i = 0; i !== 8; i++) {
  11124. var child = children[i];
  11125. // Set current node as root
  11126. child.root = root;
  11127. // Compute bounds
  11128. var lowerBound = child.aabb.lowerBound;
  11129. lowerBound.x *= halfDiagonal.x;
  11130. lowerBound.y *= halfDiagonal.y;
  11131. lowerBound.z *= halfDiagonal.z;
  11132. lowerBound.vadd(l, lowerBound);
  11133. // Upper bound is always lower bound + halfDiagonal
  11134. lowerBound.vadd(halfDiagonal, child.aabb.upperBound);
  11135. }
  11136. };
  11137. /**
  11138. * Get all data, potentially within an AABB
  11139. * @method aabbQuery
  11140. * @param {AABB} aabb
  11141. * @param {array} result
  11142. * @return {array} The "result" object
  11143. */
  11144. OctreeNode.prototype.aabbQuery = function(aabb, result) {
  11145. var nodeData = this.data;
  11146. // abort if the range does not intersect this node
  11147. // if (!this.aabb.overlaps(aabb)){
  11148. // return result;
  11149. // }
  11150. // Add objects at this level
  11151. // Array.prototype.push.apply(result, nodeData);
  11152. // Add child data
  11153. // @todo unwrap recursion into a queue / loop, that's faster in JS
  11154. var children = this.children;
  11155. // for (var i = 0, N = this.children.length; i !== N; i++) {
  11156. // children[i].aabbQuery(aabb, result);
  11157. // }
  11158. var queue = [this];
  11159. while (queue.length) {
  11160. var node = queue.pop();
  11161. if (node.aabb.overlaps(aabb)){
  11162. Array.prototype.push.apply(result, node.data);
  11163. }
  11164. Array.prototype.push.apply(queue, node.children);
  11165. }
  11166. return result;
  11167. };
  11168. var tmpAABB = new AABB();
  11169. /**
  11170. * Get all data, potentially intersected by a ray.
  11171. * @method rayQuery
  11172. * @param {Ray} ray
  11173. * @param {Transform} treeTransform
  11174. * @param {array} result
  11175. * @return {array} The "result" object
  11176. */
  11177. OctreeNode.prototype.rayQuery = function(ray, treeTransform, result) {
  11178. // Use aabb query for now.
  11179. // @todo implement real ray query which needs less lookups
  11180. ray.getAABB(tmpAABB);
  11181. tmpAABB.toLocalFrame(treeTransform, tmpAABB);
  11182. this.aabbQuery(tmpAABB, result);
  11183. return result;
  11184. };
  11185. /**
  11186. * @method removeEmptyNodes
  11187. */
  11188. OctreeNode.prototype.removeEmptyNodes = function() {
  11189. var queue = [this];
  11190. while (queue.length) {
  11191. var node = queue.pop();
  11192. for (var i = node.children.length - 1; i >= 0; i--) {
  11193. if(!node.children[i].data.length){
  11194. node.children.splice(i, 1);
  11195. }
  11196. }
  11197. Array.prototype.push.apply(queue, node.children);
  11198. }
  11199. };
  11200. },{"../collision/AABB":18,"../math/Vec3":46}],67:[function(require,module,exports){
  11201. module.exports = Pool;
  11202. /**
  11203. * For pooling objects that can be reused.
  11204. * @class Pool
  11205. * @constructor
  11206. */
  11207. function Pool(){
  11208. /**
  11209. * The pooled objects
  11210. * @property {Array} objects
  11211. */
  11212. this.objects = [];
  11213. /**
  11214. * Constructor of the objects
  11215. * @property {mixed} type
  11216. */
  11217. this.type = Object;
  11218. }
  11219. /**
  11220. * Release an object after use
  11221. * @method release
  11222. * @param {Object} obj
  11223. */
  11224. Pool.prototype.release = function(){
  11225. var Nargs = arguments.length;
  11226. for(var i=0; i!==Nargs; i++){
  11227. this.objects.push(arguments[i]);
  11228. }
  11229. return this;
  11230. };
  11231. /**
  11232. * Get an object
  11233. * @method get
  11234. * @return {mixed}
  11235. */
  11236. Pool.prototype.get = function(){
  11237. if(this.objects.length===0){
  11238. return this.constructObject();
  11239. } else {
  11240. return this.objects.pop();
  11241. }
  11242. };
  11243. /**
  11244. * Construct an object. Should be implmented in each subclass.
  11245. * @method constructObject
  11246. * @return {mixed}
  11247. */
  11248. Pool.prototype.constructObject = function(){
  11249. throw new Error("constructObject() not implemented in this Pool subclass yet!");
  11250. };
  11251. /**
  11252. * @method resize
  11253. * @param {number} size
  11254. * @return {Pool} Self, for chaining
  11255. */
  11256. Pool.prototype.resize = function (size) {
  11257. var objects = this.objects;
  11258. while (objects.length > size) {
  11259. objects.pop();
  11260. }
  11261. while (objects.length < size) {
  11262. objects.push(this.constructObject());
  11263. }
  11264. return this;
  11265. };
  11266. },{}],68:[function(require,module,exports){
  11267. module.exports = TupleDictionary;
  11268. /**
  11269. * @class TupleDictionary
  11270. * @constructor
  11271. */
  11272. function TupleDictionary() {
  11273. /**
  11274. * The data storage
  11275. * @property data
  11276. * @type {Object}
  11277. */
  11278. this.data = { keys:[] };
  11279. }
  11280. /**
  11281. * @method get
  11282. * @param {Number} i
  11283. * @param {Number} j
  11284. * @return {Number}
  11285. */
  11286. TupleDictionary.prototype.get = function(i, j) {
  11287. if (i > j) {
  11288. // swap
  11289. var temp = j;
  11290. j = i;
  11291. i = temp;
  11292. }
  11293. return this.data[i+'-'+j];
  11294. };
  11295. /**
  11296. * @method set
  11297. * @param {Number} i
  11298. * @param {Number} j
  11299. * @param {Number} value
  11300. */
  11301. TupleDictionary.prototype.set = function(i, j, value) {
  11302. if (i > j) {
  11303. var temp = j;
  11304. j = i;
  11305. i = temp;
  11306. }
  11307. var key = i+'-'+j;
  11308. // Check if key already exists
  11309. if(!this.get(i,j)){
  11310. this.data.keys.push(key);
  11311. }
  11312. this.data[key] = value;
  11313. };
  11314. /**
  11315. * @method reset
  11316. */
  11317. TupleDictionary.prototype.reset = function() {
  11318. var data = this.data,
  11319. keys = data.keys;
  11320. while(keys.length > 0){
  11321. var key = keys.pop();
  11322. delete data[key];
  11323. }
  11324. };
  11325. },{}],69:[function(require,module,exports){
  11326. function Utils(){}
  11327. module.exports = Utils;
  11328. /**
  11329. * Extend an options object with default values.
  11330. * @static
  11331. * @method defaults
  11332. * @param {object} options The options object. May be falsy: in this case, a new object is created and returned.
  11333. * @param {object} defaults An object containing default values.
  11334. * @return {object} The modified options object.
  11335. */
  11336. Utils.defaults = function(options, defaults){
  11337. options = options || {};
  11338. for(var key in defaults){
  11339. if(!(key in options)){
  11340. options[key] = defaults[key];
  11341. }
  11342. }
  11343. return options;
  11344. };
  11345. },{}],70:[function(require,module,exports){
  11346. module.exports = Vec3Pool;
  11347. var Vec3 = require('../math/Vec3');
  11348. var Pool = require('./Pool');
  11349. /**
  11350. * @class Vec3Pool
  11351. * @constructor
  11352. * @extends Pool
  11353. */
  11354. function Vec3Pool(){
  11355. Pool.call(this);
  11356. this.type = Vec3;
  11357. }
  11358. Vec3Pool.prototype = new Pool();
  11359. /**
  11360. * Construct a vector
  11361. * @method constructObject
  11362. * @return {Vec3}
  11363. */
  11364. Vec3Pool.prototype.constructObject = function(){
  11365. return new Vec3();
  11366. };
  11367. },{"../math/Vec3":46,"./Pool":67}],71:[function(require,module,exports){
  11368. module.exports = Narrowphase;
  11369. var AABB = require('../collision/AABB');
  11370. var Body = require('../objects/Body');
  11371. var Shape = require('../shapes/Shape');
  11372. var Ray = require('../collision/Ray');
  11373. var Vec3 = require('../math/Vec3');
  11374. var Transform = require('../math/Transform');
  11375. var ConvexPolyhedron = require('../shapes/ConvexPolyhedron');
  11376. var Quaternion = require('../math/Quaternion');
  11377. var Solver = require('../solver/Solver');
  11378. var Vec3Pool = require('../utils/Vec3Pool');
  11379. var ContactEquation = require('../equations/ContactEquation');
  11380. var FrictionEquation = require('../equations/FrictionEquation');
  11381. /**
  11382. * Helper class for the World. Generates ContactEquations.
  11383. * @class Narrowphase
  11384. * @constructor
  11385. * @todo Sphere-ConvexPolyhedron contacts
  11386. * @todo Contact reduction
  11387. * @todo should move methods to prototype
  11388. */
  11389. function Narrowphase(world){
  11390. /**
  11391. * Internal storage of pooled contact points.
  11392. * @property {Array} contactPointPool
  11393. */
  11394. this.contactPointPool = [];
  11395. this.frictionEquationPool = [];
  11396. this.result = [];
  11397. this.frictionResult = [];
  11398. /**
  11399. * Pooled vectors.
  11400. * @property {Vec3Pool} v3pool
  11401. */
  11402. this.v3pool = new Vec3Pool();
  11403. this.world = world;
  11404. this.currentContactMaterial = null;
  11405. /**
  11406. * @property {Boolean} enableFrictionReduction
  11407. */
  11408. this.enableFrictionReduction = false;
  11409. }
  11410. /**
  11411. * Make a contact object, by using the internal pool or creating a new one.
  11412. * @method createContactEquation
  11413. * @param {Body} bi
  11414. * @param {Body} bj
  11415. * @param {Shape} si
  11416. * @param {Shape} sj
  11417. * @param {Shape} overrideShapeA
  11418. * @param {Shape} overrideShapeB
  11419. * @return {ContactEquation}
  11420. */
  11421. Narrowphase.prototype.createContactEquation = function(bi, bj, si, sj, overrideShapeA, overrideShapeB){
  11422. var c;
  11423. if(this.contactPointPool.length){
  11424. c = this.contactPointPool.pop();
  11425. c.bi = bi;
  11426. c.bj = bj;
  11427. } else {
  11428. c = new ContactEquation(bi, bj);
  11429. }
  11430. c.enabled = bi.collisionResponse && bj.collisionResponse && si.collisionResponse && sj.collisionResponse;
  11431. var cm = this.currentContactMaterial;
  11432. c.restitution = cm.restitution;
  11433. c.setSpookParams(
  11434. cm.contactEquationStiffness,
  11435. cm.contactEquationRelaxation,
  11436. this.world.dt
  11437. );
  11438. var matA = si.material || bi.material;
  11439. var matB = sj.material || bj.material;
  11440. if(matA && matB && matA.restitution >= 0 && matB.restitution >= 0){
  11441. c.restitution = matA.restitution * matB.restitution;
  11442. }
  11443. c.si = overrideShapeA || si;
  11444. c.sj = overrideShapeB || sj;
  11445. return c;
  11446. };
  11447. Narrowphase.prototype.createFrictionEquationsFromContact = function(contactEquation, outArray){
  11448. var bodyA = contactEquation.bi;
  11449. var bodyB = contactEquation.bj;
  11450. var shapeA = contactEquation.si;
  11451. var shapeB = contactEquation.sj;
  11452. var world = this.world;
  11453. var cm = this.currentContactMaterial;
  11454. // If friction or restitution were specified in the material, use them
  11455. var friction = cm.friction;
  11456. var matA = shapeA.material || bodyA.material;
  11457. var matB = shapeB.material || bodyB.material;
  11458. if(matA && matB && matA.friction >= 0 && matB.friction >= 0){
  11459. friction = matA.friction * matB.friction;
  11460. }
  11461. if(friction > 0){
  11462. // Create 2 tangent equations
  11463. var mug = friction * world.gravity.length();
  11464. var reducedMass = (bodyA.invMass + bodyB.invMass);
  11465. if(reducedMass > 0){
  11466. reducedMass = 1/reducedMass;
  11467. }
  11468. var pool = this.frictionEquationPool;
  11469. var c1 = pool.length ? pool.pop() : new FrictionEquation(bodyA,bodyB,mug*reducedMass);
  11470. var c2 = pool.length ? pool.pop() : new FrictionEquation(bodyA,bodyB,mug*reducedMass);
  11471. c1.bi = c2.bi = bodyA;
  11472. c1.bj = c2.bj = bodyB;
  11473. c1.minForce = c2.minForce = -mug*reducedMass;
  11474. c1.maxForce = c2.maxForce = mug*reducedMass;
  11475. // Copy over the relative vectors
  11476. c1.ri.copy(contactEquation.ri);
  11477. c1.rj.copy(contactEquation.rj);
  11478. c2.ri.copy(contactEquation.ri);
  11479. c2.rj.copy(contactEquation.rj);
  11480. // Construct tangents
  11481. contactEquation.ni.tangents(c1.t, c2.t);
  11482. // Set spook params
  11483. c1.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, world.dt);
  11484. c2.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, world.dt);
  11485. c1.enabled = c2.enabled = contactEquation.enabled;
  11486. outArray.push(c1, c2);
  11487. return true;
  11488. }
  11489. return false;
  11490. };
  11491. var averageNormal = new Vec3();
  11492. var averageContactPointA = new Vec3();
  11493. var averageContactPointB = new Vec3();
  11494. // Take the average N latest contact point on the plane.
  11495. Narrowphase.prototype.createFrictionFromAverage = function(numContacts){
  11496. // The last contactEquation
  11497. var c = this.result[this.result.length - 1];
  11498. // Create the result: two "average" friction equations
  11499. if (!this.createFrictionEquationsFromContact(c, this.frictionResult) || numContacts === 1) {
  11500. return;
  11501. }
  11502. var f1 = this.frictionResult[this.frictionResult.length - 2];
  11503. var f2 = this.frictionResult[this.frictionResult.length - 1];
  11504. averageNormal.setZero();
  11505. averageContactPointA.setZero();
  11506. averageContactPointB.setZero();
  11507. var bodyA = c.bi;
  11508. var bodyB = c.bj;
  11509. for(var i=0; i!==numContacts; i++){
  11510. c = this.result[this.result.length - 1 - i];
  11511. if(c.bodyA !== bodyA){
  11512. averageNormal.vadd(c.ni, averageNormal);
  11513. averageContactPointA.vadd(c.ri, averageContactPointA);
  11514. averageContactPointB.vadd(c.rj, averageContactPointB);
  11515. } else {
  11516. averageNormal.vsub(c.ni, averageNormal);
  11517. averageContactPointA.vadd(c.rj, averageContactPointA);
  11518. averageContactPointB.vadd(c.ri, averageContactPointB);
  11519. }
  11520. }
  11521. var invNumContacts = 1 / numContacts;
  11522. averageContactPointA.scale(invNumContacts, f1.ri);
  11523. averageContactPointB.scale(invNumContacts, f1.rj);
  11524. f2.ri.copy(f1.ri); // Should be the same
  11525. f2.rj.copy(f1.rj);
  11526. averageNormal.normalize();
  11527. averageNormal.tangents(f1.t, f2.t);
  11528. // return eq;
  11529. };
  11530. var tmpVec1 = new Vec3();
  11531. var tmpVec2 = new Vec3();
  11532. var tmpQuat1 = new Quaternion();
  11533. var tmpQuat2 = new Quaternion();
  11534. /**
  11535. * Generate all contacts between a list of body pairs
  11536. * @method getContacts
  11537. * @param {array} p1 Array of body indices
  11538. * @param {array} p2 Array of body indices
  11539. * @param {World} world
  11540. * @param {array} result Array to store generated contacts
  11541. * @param {array} oldcontacts Optional. Array of reusable contact objects
  11542. */
  11543. Narrowphase.prototype.getContacts = function(p1, p2, world, result, oldcontacts, frictionResult, frictionPool){
  11544. // Save old contact objects
  11545. this.contactPointPool = oldcontacts;
  11546. this.frictionEquationPool = frictionPool;
  11547. this.result = result;
  11548. this.frictionResult = frictionResult;
  11549. var qi = tmpQuat1;
  11550. var qj = tmpQuat2;
  11551. var xi = tmpVec1;
  11552. var xj = tmpVec2;
  11553. for(var k=0, N=p1.length; k!==N; k++){
  11554. // Get current collision bodies
  11555. var bi = p1[k],
  11556. bj = p2[k];
  11557. // Get contact material
  11558. var bodyContactMaterial = null;
  11559. if(bi.material && bj.material){
  11560. bodyContactMaterial = world.getContactMaterial(bi.material,bj.material) || null;
  11561. }
  11562. var justTest = (
  11563. (
  11564. (bi.type & Body.KINEMATIC) && (bj.type & Body.STATIC)
  11565. ) || (
  11566. (bi.type & Body.STATIC) && (bj.type & Body.KINEMATIC)
  11567. ) || (
  11568. (bi.type & Body.KINEMATIC) && (bj.type & Body.KINEMATIC)
  11569. )
  11570. );
  11571. for (var i = 0; i < bi.shapes.length; i++) {
  11572. bi.quaternion.mult(bi.shapeOrientations[i], qi);
  11573. bi.quaternion.vmult(bi.shapeOffsets[i], xi);
  11574. xi.vadd(bi.position, xi);
  11575. var si = bi.shapes[i];
  11576. for (var j = 0; j < bj.shapes.length; j++) {
  11577. // Compute world transform of shapes
  11578. bj.quaternion.mult(bj.shapeOrientations[j], qj);
  11579. bj.quaternion.vmult(bj.shapeOffsets[j], xj);
  11580. xj.vadd(bj.position, xj);
  11581. var sj = bj.shapes[j];
  11582. if(xi.distanceTo(xj) > si.boundingSphereRadius + sj.boundingSphereRadius){
  11583. continue;
  11584. }
  11585. // Get collision material
  11586. var shapeContactMaterial = null;
  11587. if(si.material && sj.material){
  11588. shapeContactMaterial = world.getContactMaterial(si.material,sj.material) || null;
  11589. }
  11590. this.currentContactMaterial = shapeContactMaterial || bodyContactMaterial || world.defaultContactMaterial;
  11591. // Get contacts
  11592. var resolver = this[si.type | sj.type];
  11593. if(resolver){
  11594. var retval = false;
  11595. if (si.type < sj.type) {
  11596. retval = resolver.call(this, si, sj, xi, xj, qi, qj, bi, bj, si, sj, justTest);
  11597. } else {
  11598. retval = resolver.call(this, sj, si, xj, xi, qj, qi, bj, bi, si, sj, justTest);
  11599. }
  11600. if(retval && justTest){
  11601. // Register overlap
  11602. world.shapeOverlapKeeper.set(si.id, sj.id);
  11603. world.bodyOverlapKeeper.set(bi.id, bj.id);
  11604. }
  11605. }
  11606. }
  11607. }
  11608. }
  11609. };
  11610. var numWarnings = 0;
  11611. var maxWarnings = 10;
  11612. function warn(msg){
  11613. if(numWarnings > maxWarnings){
  11614. return;
  11615. }
  11616. numWarnings++;
  11617. console.warn(msg);
  11618. }
  11619. Narrowphase.prototype[Shape.types.BOX | Shape.types.BOX] =
  11620. Narrowphase.prototype.boxBox = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  11621. si.convexPolyhedronRepresentation.material = si.material;
  11622. sj.convexPolyhedronRepresentation.material = sj.material;
  11623. si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
  11624. sj.convexPolyhedronRepresentation.collisionResponse = sj.collisionResponse;
  11625. return this.convexConvex(si.convexPolyhedronRepresentation,sj.convexPolyhedronRepresentation,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  11626. };
  11627. Narrowphase.prototype[Shape.types.BOX | Shape.types.CONVEXPOLYHEDRON] =
  11628. Narrowphase.prototype.boxConvex = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  11629. si.convexPolyhedronRepresentation.material = si.material;
  11630. si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
  11631. return this.convexConvex(si.convexPolyhedronRepresentation,sj,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  11632. };
  11633. Narrowphase.prototype[Shape.types.BOX | Shape.types.PARTICLE] =
  11634. Narrowphase.prototype.boxParticle = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  11635. si.convexPolyhedronRepresentation.material = si.material;
  11636. si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
  11637. return this.convexParticle(si.convexPolyhedronRepresentation,sj,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  11638. };
  11639. /**
  11640. * @method sphereSphere
  11641. * @param {Shape} si
  11642. * @param {Shape} sj
  11643. * @param {Vec3} xi
  11644. * @param {Vec3} xj
  11645. * @param {Quaternion} qi
  11646. * @param {Quaternion} qj
  11647. * @param {Body} bi
  11648. * @param {Body} bj
  11649. */
  11650. Narrowphase.prototype[Shape.types.SPHERE] =
  11651. Narrowphase.prototype.sphereSphere = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  11652. if(justTest){
  11653. return xi.distanceSquared(xj) < Math.pow(si.radius + sj.radius, 2);
  11654. }
  11655. // We will have only one contact in this case
  11656. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  11657. // Contact normal
  11658. xj.vsub(xi, r.ni);
  11659. r.ni.normalize();
  11660. // Contact point locations
  11661. r.ri.copy(r.ni);
  11662. r.rj.copy(r.ni);
  11663. r.ri.mult(si.radius, r.ri);
  11664. r.rj.mult(-sj.radius, r.rj);
  11665. r.ri.vadd(xi, r.ri);
  11666. r.ri.vsub(bi.position, r.ri);
  11667. r.rj.vadd(xj, r.rj);
  11668. r.rj.vsub(bj.position, r.rj);
  11669. this.result.push(r);
  11670. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11671. };
  11672. /**
  11673. * @method planeTrimesh
  11674. * @param {Shape} si
  11675. * @param {Shape} sj
  11676. * @param {Vec3} xi
  11677. * @param {Vec3} xj
  11678. * @param {Quaternion} qi
  11679. * @param {Quaternion} qj
  11680. * @param {Body} bi
  11681. * @param {Body} bj
  11682. */
  11683. var planeTrimesh_normal = new Vec3();
  11684. var planeTrimesh_relpos = new Vec3();
  11685. var planeTrimesh_projected = new Vec3();
  11686. Narrowphase.prototype[Shape.types.PLANE | Shape.types.TRIMESH] =
  11687. Narrowphase.prototype.planeTrimesh = function(
  11688. planeShape,
  11689. trimeshShape,
  11690. planePos,
  11691. trimeshPos,
  11692. planeQuat,
  11693. trimeshQuat,
  11694. planeBody,
  11695. trimeshBody,
  11696. rsi,
  11697. rsj,
  11698. justTest
  11699. ){
  11700. // Make contacts!
  11701. var v = new Vec3();
  11702. var normal = planeTrimesh_normal;
  11703. normal.set(0,0,1);
  11704. planeQuat.vmult(normal,normal); // Turn normal according to plane
  11705. for(var i=0; i<trimeshShape.vertices.length / 3; i++){
  11706. // Get world vertex from trimesh
  11707. trimeshShape.getVertex(i, v);
  11708. // Safe up
  11709. var v2 = new Vec3();
  11710. v2.copy(v);
  11711. Transform.pointToWorldFrame(trimeshPos, trimeshQuat, v2, v);
  11712. // Check plane side
  11713. var relpos = planeTrimesh_relpos;
  11714. v.vsub(planePos, relpos);
  11715. var dot = normal.dot(relpos);
  11716. if(dot <= 0.0){
  11717. if(justTest){
  11718. return true;
  11719. }
  11720. var r = this.createContactEquation(planeBody,trimeshBody,planeShape,trimeshShape,rsi,rsj);
  11721. r.ni.copy(normal); // Contact normal is the plane normal
  11722. // Get vertex position projected on plane
  11723. var projected = planeTrimesh_projected;
  11724. normal.scale(relpos.dot(normal), projected);
  11725. v.vsub(projected,projected);
  11726. // ri is the projected world position minus plane position
  11727. r.ri.copy(projected);
  11728. r.ri.vsub(planeBody.position, r.ri);
  11729. r.rj.copy(v);
  11730. r.rj.vsub(trimeshBody.position, r.rj);
  11731. // Store result
  11732. this.result.push(r);
  11733. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11734. }
  11735. }
  11736. };
  11737. /**
  11738. * @method sphereTrimesh
  11739. * @param {Shape} sphereShape
  11740. * @param {Shape} trimeshShape
  11741. * @param {Vec3} spherePos
  11742. * @param {Vec3} trimeshPos
  11743. * @param {Quaternion} sphereQuat
  11744. * @param {Quaternion} trimeshQuat
  11745. * @param {Body} sphereBody
  11746. * @param {Body} trimeshBody
  11747. */
  11748. var sphereTrimesh_normal = new Vec3();
  11749. var sphereTrimesh_relpos = new Vec3();
  11750. var sphereTrimesh_projected = new Vec3();
  11751. var sphereTrimesh_v = new Vec3();
  11752. var sphereTrimesh_v2 = new Vec3();
  11753. var sphereTrimesh_edgeVertexA = new Vec3();
  11754. var sphereTrimesh_edgeVertexB = new Vec3();
  11755. var sphereTrimesh_edgeVector = new Vec3();
  11756. var sphereTrimesh_edgeVectorUnit = new Vec3();
  11757. var sphereTrimesh_localSpherePos = new Vec3();
  11758. var sphereTrimesh_tmp = new Vec3();
  11759. var sphereTrimesh_va = new Vec3();
  11760. var sphereTrimesh_vb = new Vec3();
  11761. var sphereTrimesh_vc = new Vec3();
  11762. var sphereTrimesh_localSphereAABB = new AABB();
  11763. var sphereTrimesh_triangles = [];
  11764. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.TRIMESH] =
  11765. Narrowphase.prototype.sphereTrimesh = function (
  11766. sphereShape,
  11767. trimeshShape,
  11768. spherePos,
  11769. trimeshPos,
  11770. sphereQuat,
  11771. trimeshQuat,
  11772. sphereBody,
  11773. trimeshBody,
  11774. rsi,
  11775. rsj,
  11776. justTest
  11777. ) {
  11778. var edgeVertexA = sphereTrimesh_edgeVertexA;
  11779. var edgeVertexB = sphereTrimesh_edgeVertexB;
  11780. var edgeVector = sphereTrimesh_edgeVector;
  11781. var edgeVectorUnit = sphereTrimesh_edgeVectorUnit;
  11782. var localSpherePos = sphereTrimesh_localSpherePos;
  11783. var tmp = sphereTrimesh_tmp;
  11784. var localSphereAABB = sphereTrimesh_localSphereAABB;
  11785. var v2 = sphereTrimesh_v2;
  11786. var relpos = sphereTrimesh_relpos;
  11787. var triangles = sphereTrimesh_triangles;
  11788. // Convert sphere position to local in the trimesh
  11789. Transform.pointToLocalFrame(trimeshPos, trimeshQuat, spherePos, localSpherePos);
  11790. // Get the aabb of the sphere locally in the trimesh
  11791. var sphereRadius = sphereShape.radius;
  11792. localSphereAABB.lowerBound.set(
  11793. localSpherePos.x - sphereRadius,
  11794. localSpherePos.y - sphereRadius,
  11795. localSpherePos.z - sphereRadius
  11796. );
  11797. localSphereAABB.upperBound.set(
  11798. localSpherePos.x + sphereRadius,
  11799. localSpherePos.y + sphereRadius,
  11800. localSpherePos.z + sphereRadius
  11801. );
  11802. trimeshShape.getTrianglesInAABB(localSphereAABB, triangles);
  11803. //for (var i = 0; i < trimeshShape.indices.length / 3; i++) triangles.push(i); // All
  11804. // Vertices
  11805. var v = sphereTrimesh_v;
  11806. var radiusSquared = sphereShape.radius * sphereShape.radius;
  11807. for(var i=0; i<triangles.length; i++){
  11808. for (var j = 0; j < 3; j++) {
  11809. trimeshShape.getVertex(trimeshShape.indices[triangles[i] * 3 + j], v);
  11810. // Check vertex overlap in sphere
  11811. v.vsub(localSpherePos, relpos);
  11812. if(relpos.norm2() <= radiusSquared){
  11813. // Safe up
  11814. v2.copy(v);
  11815. Transform.pointToWorldFrame(trimeshPos, trimeshQuat, v2, v);
  11816. v.vsub(spherePos, relpos);
  11817. if(justTest){
  11818. return true;
  11819. }
  11820. var r = this.createContactEquation(sphereBody,trimeshBody,sphereShape,trimeshShape,rsi,rsj);
  11821. r.ni.copy(relpos);
  11822. r.ni.normalize();
  11823. // ri is the vector from sphere center to the sphere surface
  11824. r.ri.copy(r.ni);
  11825. r.ri.scale(sphereShape.radius, r.ri);
  11826. r.ri.vadd(spherePos, r.ri);
  11827. r.ri.vsub(sphereBody.position, r.ri);
  11828. r.rj.copy(v);
  11829. r.rj.vsub(trimeshBody.position, r.rj);
  11830. // Store result
  11831. this.result.push(r);
  11832. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11833. }
  11834. }
  11835. }
  11836. // Check all edges
  11837. for(var i=0; i<triangles.length; i++){
  11838. for (var j = 0; j < 3; j++) {
  11839. trimeshShape.getVertex(trimeshShape.indices[triangles[i] * 3 + j], edgeVertexA);
  11840. trimeshShape.getVertex(trimeshShape.indices[triangles[i] * 3 + ((j+1)%3)], edgeVertexB);
  11841. edgeVertexB.vsub(edgeVertexA, edgeVector);
  11842. // Project sphere position to the edge
  11843. localSpherePos.vsub(edgeVertexB, tmp);
  11844. var positionAlongEdgeB = tmp.dot(edgeVector);
  11845. localSpherePos.vsub(edgeVertexA, tmp);
  11846. var positionAlongEdgeA = tmp.dot(edgeVector);
  11847. if(positionAlongEdgeA > 0 && positionAlongEdgeB < 0){
  11848. // Now check the orthogonal distance from edge to sphere center
  11849. localSpherePos.vsub(edgeVertexA, tmp);
  11850. edgeVectorUnit.copy(edgeVector);
  11851. edgeVectorUnit.normalize();
  11852. positionAlongEdgeA = tmp.dot(edgeVectorUnit);
  11853. edgeVectorUnit.scale(positionAlongEdgeA, tmp);
  11854. tmp.vadd(edgeVertexA, tmp);
  11855. // tmp is now the sphere center position projected to the edge, defined locally in the trimesh frame
  11856. var dist = tmp.distanceTo(localSpherePos);
  11857. if(dist < sphereShape.radius){
  11858. if(justTest){
  11859. return true;
  11860. }
  11861. var r = this.createContactEquation(sphereBody, trimeshBody, sphereShape, trimeshShape,rsi,rsj);
  11862. tmp.vsub(localSpherePos, r.ni);
  11863. r.ni.normalize();
  11864. r.ni.scale(sphereShape.radius, r.ri);
  11865. Transform.pointToWorldFrame(trimeshPos, trimeshQuat, tmp, tmp);
  11866. tmp.vsub(trimeshBody.position, r.rj);
  11867. Transform.vectorToWorldFrame(trimeshQuat, r.ni, r.ni);
  11868. Transform.vectorToWorldFrame(trimeshQuat, r.ri, r.ri);
  11869. this.result.push(r);
  11870. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11871. }
  11872. }
  11873. }
  11874. }
  11875. // Triangle faces
  11876. var va = sphereTrimesh_va;
  11877. var vb = sphereTrimesh_vb;
  11878. var vc = sphereTrimesh_vc;
  11879. var normal = sphereTrimesh_normal;
  11880. for(var i=0, N = triangles.length; i !== N; i++){
  11881. trimeshShape.getTriangleVertices(triangles[i], va, vb, vc);
  11882. trimeshShape.getNormal(triangles[i], normal);
  11883. localSpherePos.vsub(va, tmp);
  11884. var dist = tmp.dot(normal);
  11885. normal.scale(dist, tmp);
  11886. localSpherePos.vsub(tmp, tmp);
  11887. // tmp is now the sphere position projected to the triangle plane
  11888. dist = tmp.distanceTo(localSpherePos);
  11889. if(Ray.pointInTriangle(tmp, va, vb, vc) && dist < sphereShape.radius){
  11890. if(justTest){
  11891. return true;
  11892. }
  11893. var r = this.createContactEquation(sphereBody, trimeshBody, sphereShape, trimeshShape,rsi,rsj);
  11894. tmp.vsub(localSpherePos, r.ni);
  11895. r.ni.normalize();
  11896. r.ni.scale(sphereShape.radius, r.ri);
  11897. Transform.pointToWorldFrame(trimeshPos, trimeshQuat, tmp, tmp);
  11898. tmp.vsub(trimeshBody.position, r.rj);
  11899. Transform.vectorToWorldFrame(trimeshQuat, r.ni, r.ni);
  11900. Transform.vectorToWorldFrame(trimeshQuat, r.ri, r.ri);
  11901. this.result.push(r);
  11902. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11903. }
  11904. }
  11905. triangles.length = 0;
  11906. };
  11907. var point_on_plane_to_sphere = new Vec3();
  11908. var plane_to_sphere_ortho = new Vec3();
  11909. /**
  11910. * @method spherePlane
  11911. * @param {Shape} si
  11912. * @param {Shape} sj
  11913. * @param {Vec3} xi
  11914. * @param {Vec3} xj
  11915. * @param {Quaternion} qi
  11916. * @param {Quaternion} qj
  11917. * @param {Body} bi
  11918. * @param {Body} bj
  11919. */
  11920. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.PLANE] =
  11921. Narrowphase.prototype.spherePlane = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  11922. // We will have one contact in this case
  11923. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  11924. // Contact normal
  11925. r.ni.set(0,0,1);
  11926. qj.vmult(r.ni, r.ni);
  11927. r.ni.negate(r.ni); // body i is the sphere, flip normal
  11928. r.ni.normalize(); // Needed?
  11929. // Vector from sphere center to contact point
  11930. r.ni.mult(si.radius, r.ri);
  11931. // Project down sphere on plane
  11932. xi.vsub(xj, point_on_plane_to_sphere);
  11933. r.ni.mult(r.ni.dot(point_on_plane_to_sphere), plane_to_sphere_ortho);
  11934. point_on_plane_to_sphere.vsub(plane_to_sphere_ortho,r.rj); // The sphere position projected to plane
  11935. if(-point_on_plane_to_sphere.dot(r.ni) <= si.radius){
  11936. if(justTest){
  11937. return true;
  11938. }
  11939. // Make it relative to the body
  11940. var ri = r.ri;
  11941. var rj = r.rj;
  11942. ri.vadd(xi, ri);
  11943. ri.vsub(bi.position, ri);
  11944. rj.vadd(xj, rj);
  11945. rj.vsub(bj.position, rj);
  11946. this.result.push(r);
  11947. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11948. }
  11949. };
  11950. // See http://bulletphysics.com/Bullet/BulletFull/SphereTriangleDetector_8cpp_source.html
  11951. var pointInPolygon_edge = new Vec3();
  11952. var pointInPolygon_edge_x_normal = new Vec3();
  11953. var pointInPolygon_vtp = new Vec3();
  11954. function pointInPolygon(verts, normal, p){
  11955. var positiveResult = null;
  11956. var N = verts.length;
  11957. for(var i=0; i!==N; i++){
  11958. var v = verts[i];
  11959. // Get edge to the next vertex
  11960. var edge = pointInPolygon_edge;
  11961. verts[(i+1) % (N)].vsub(v,edge);
  11962. // Get cross product between polygon normal and the edge
  11963. var edge_x_normal = pointInPolygon_edge_x_normal;
  11964. //var edge_x_normal = new Vec3();
  11965. edge.cross(normal,edge_x_normal);
  11966. // Get vector between point and current vertex
  11967. var vertex_to_p = pointInPolygon_vtp;
  11968. p.vsub(v,vertex_to_p);
  11969. // This dot product determines which side of the edge the point is
  11970. var r = edge_x_normal.dot(vertex_to_p);
  11971. // If all such dot products have same sign, we are inside the polygon.
  11972. if(positiveResult===null || (r>0 && positiveResult===true) || (r<=0 && positiveResult===false)){
  11973. if(positiveResult===null){
  11974. positiveResult = r>0;
  11975. }
  11976. continue;
  11977. } else {
  11978. return false; // Encountered some other sign. Exit.
  11979. }
  11980. }
  11981. // If we got here, all dot products were of the same sign.
  11982. return true;
  11983. }
  11984. var box_to_sphere = new Vec3();
  11985. var sphereBox_ns = new Vec3();
  11986. var sphereBox_ns1 = new Vec3();
  11987. var sphereBox_ns2 = new Vec3();
  11988. var sphereBox_sides = [new Vec3(),new Vec3(),new Vec3(),new Vec3(),new Vec3(),new Vec3()];
  11989. var sphereBox_sphere_to_corner = new Vec3();
  11990. var sphereBox_side_ns = new Vec3();
  11991. var sphereBox_side_ns1 = new Vec3();
  11992. var sphereBox_side_ns2 = new Vec3();
  11993. /**
  11994. * @method sphereBox
  11995. * @param {Shape} si
  11996. * @param {Shape} sj
  11997. * @param {Vec3} xi
  11998. * @param {Vec3} xj
  11999. * @param {Quaternion} qi
  12000. * @param {Quaternion} qj
  12001. * @param {Body} bi
  12002. * @param {Body} bj
  12003. */
  12004. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.BOX] =
  12005. Narrowphase.prototype.sphereBox = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  12006. var v3pool = this.v3pool;
  12007. // we refer to the box as body j
  12008. var sides = sphereBox_sides;
  12009. xi.vsub(xj,box_to_sphere);
  12010. sj.getSideNormals(sides,qj);
  12011. var R = si.radius;
  12012. var penetrating_sides = [];
  12013. // Check side (plane) intersections
  12014. var found = false;
  12015. // Store the resulting side penetration info
  12016. var side_ns = sphereBox_side_ns;
  12017. var side_ns1 = sphereBox_side_ns1;
  12018. var side_ns2 = sphereBox_side_ns2;
  12019. var side_h = null;
  12020. var side_penetrations = 0;
  12021. var side_dot1 = 0;
  12022. var side_dot2 = 0;
  12023. var side_distance = null;
  12024. for(var idx=0,nsides=sides.length; idx!==nsides && found===false; idx++){
  12025. // Get the plane side normal (ns)
  12026. var ns = sphereBox_ns;
  12027. ns.copy(sides[idx]);
  12028. var h = ns.norm();
  12029. ns.normalize();
  12030. // The normal/distance dot product tells which side of the plane we are
  12031. var dot = box_to_sphere.dot(ns);
  12032. if(dot<h+R && dot>0){
  12033. // Intersects plane. Now check the other two dimensions
  12034. var ns1 = sphereBox_ns1;
  12035. var ns2 = sphereBox_ns2;
  12036. ns1.copy(sides[(idx+1)%3]);
  12037. ns2.copy(sides[(idx+2)%3]);
  12038. var h1 = ns1.norm();
  12039. var h2 = ns2.norm();
  12040. ns1.normalize();
  12041. ns2.normalize();
  12042. var dot1 = box_to_sphere.dot(ns1);
  12043. var dot2 = box_to_sphere.dot(ns2);
  12044. if(dot1<h1 && dot1>-h1 && dot2<h2 && dot2>-h2){
  12045. var dist = Math.abs(dot-h-R);
  12046. if(side_distance===null || dist < side_distance){
  12047. side_distance = dist;
  12048. side_dot1 = dot1;
  12049. side_dot2 = dot2;
  12050. side_h = h;
  12051. side_ns.copy(ns);
  12052. side_ns1.copy(ns1);
  12053. side_ns2.copy(ns2);
  12054. side_penetrations++;
  12055. if(justTest){
  12056. return true;
  12057. }
  12058. }
  12059. }
  12060. }
  12061. }
  12062. if(side_penetrations){
  12063. found = true;
  12064. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  12065. side_ns.mult(-R,r.ri); // Sphere r
  12066. r.ni.copy(side_ns);
  12067. r.ni.negate(r.ni); // Normal should be out of sphere
  12068. side_ns.mult(side_h,side_ns);
  12069. side_ns1.mult(side_dot1,side_ns1);
  12070. side_ns.vadd(side_ns1,side_ns);
  12071. side_ns2.mult(side_dot2,side_ns2);
  12072. side_ns.vadd(side_ns2,r.rj);
  12073. // Make relative to bodies
  12074. r.ri.vadd(xi, r.ri);
  12075. r.ri.vsub(bi.position, r.ri);
  12076. r.rj.vadd(xj, r.rj);
  12077. r.rj.vsub(bj.position, r.rj);
  12078. this.result.push(r);
  12079. this.createFrictionEquationsFromContact(r, this.frictionResult);
  12080. }
  12081. // Check corners
  12082. var rj = v3pool.get();
  12083. var sphere_to_corner = sphereBox_sphere_to_corner;
  12084. for(var j=0; j!==2 && !found; j++){
  12085. for(var k=0; k!==2 && !found; k++){
  12086. for(var l=0; l!==2 && !found; l++){
  12087. rj.set(0,0,0);
  12088. if(j){
  12089. rj.vadd(sides[0],rj);
  12090. } else {
  12091. rj.vsub(sides[0],rj);
  12092. }
  12093. if(k){
  12094. rj.vadd(sides[1],rj);
  12095. } else {
  12096. rj.vsub(sides[1],rj);
  12097. }
  12098. if(l){
  12099. rj.vadd(sides[2],rj);
  12100. } else {
  12101. rj.vsub(sides[2],rj);
  12102. }
  12103. // World position of corner
  12104. xj.vadd(rj,sphere_to_corner);
  12105. sphere_to_corner.vsub(xi,sphere_to_corner);
  12106. if(sphere_to_corner.norm2() < R*R){
  12107. if(justTest){
  12108. return true;
  12109. }
  12110. found = true;
  12111. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  12112. r.ri.copy(sphere_to_corner);
  12113. r.ri.normalize();
  12114. r.ni.copy(r.ri);
  12115. r.ri.mult(R,r.ri);
  12116. r.rj.copy(rj);
  12117. // Make relative to bodies
  12118. r.ri.vadd(xi, r.ri);
  12119. r.ri.vsub(bi.position, r.ri);
  12120. r.rj.vadd(xj, r.rj);
  12121. r.rj.vsub(bj.position, r.rj);
  12122. this.result.push(r);
  12123. this.createFrictionEquationsFromContact(r, this.frictionResult);
  12124. }
  12125. }
  12126. }
  12127. }
  12128. v3pool.release(rj);
  12129. rj = null;
  12130. // Check edges
  12131. var edgeTangent = v3pool.get();
  12132. var edgeCenter = v3pool.get();
  12133. var r = v3pool.get(); // r = edge center to sphere center
  12134. var orthogonal = v3pool.get();
  12135. var dist = v3pool.get();
  12136. var Nsides = sides.length;
  12137. for(var j=0; j!==Nsides && !found; j++){
  12138. for(var k=0; k!==Nsides && !found; k++){
  12139. if(j%3 !== k%3){
  12140. // Get edge tangent
  12141. sides[k].cross(sides[j],edgeTangent);
  12142. edgeTangent.normalize();
  12143. sides[j].vadd(sides[k], edgeCenter);
  12144. r.copy(xi);
  12145. r.vsub(edgeCenter,r);
  12146. r.vsub(xj,r);
  12147. var orthonorm = r.dot(edgeTangent); // distance from edge center to sphere center in the tangent direction
  12148. edgeTangent.mult(orthonorm,orthogonal); // Vector from edge center to sphere center in the tangent direction
  12149. // Find the third side orthogonal to this one
  12150. var l = 0;
  12151. while(l===j%3 || l===k%3){
  12152. l++;
  12153. }
  12154. // vec from edge center to sphere projected to the plane orthogonal to the edge tangent
  12155. dist.copy(xi);
  12156. dist.vsub(orthogonal,dist);
  12157. dist.vsub(edgeCenter,dist);
  12158. dist.vsub(xj,dist);
  12159. // Distances in tangent direction and distance in the plane orthogonal to it
  12160. var tdist = Math.abs(orthonorm);
  12161. var ndist = dist.norm();
  12162. if(tdist < sides[l].norm() && ndist<R){
  12163. if(justTest){
  12164. return true;
  12165. }
  12166. found = true;
  12167. var res = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  12168. edgeCenter.vadd(orthogonal,res.rj); // box rj
  12169. res.rj.copy(res.rj);
  12170. dist.negate(res.ni);
  12171. res.ni.normalize();
  12172. res.ri.copy(res.rj);
  12173. res.ri.vadd(xj,res.ri);
  12174. res.ri.vsub(xi,res.ri);
  12175. res.ri.normalize();
  12176. res.ri.mult(R,res.ri);
  12177. // Make relative to bodies
  12178. res.ri.vadd(xi, res.ri);
  12179. res.ri.vsub(bi.position, res.ri);
  12180. res.rj.vadd(xj, res.rj);
  12181. res.rj.vsub(bj.position, res.rj);
  12182. this.result.push(res);
  12183. this.createFrictionEquationsFromContact(res, this.frictionResult);
  12184. }
  12185. }
  12186. }
  12187. }
  12188. v3pool.release(edgeTangent,edgeCenter,r,orthogonal,dist);
  12189. };
  12190. var convex_to_sphere = new Vec3();
  12191. var sphereConvex_edge = new Vec3();
  12192. var sphereConvex_edgeUnit = new Vec3();
  12193. var sphereConvex_sphereToCorner = new Vec3();
  12194. var sphereConvex_worldCorner = new Vec3();
  12195. var sphereConvex_worldNormal = new Vec3();
  12196. var sphereConvex_worldPoint = new Vec3();
  12197. var sphereConvex_worldSpherePointClosestToPlane = new Vec3();
  12198. var sphereConvex_penetrationVec = new Vec3();
  12199. var sphereConvex_sphereToWorldPoint = new Vec3();
  12200. /**
  12201. * @method sphereConvex
  12202. * @param {Shape} si
  12203. * @param {Shape} sj
  12204. * @param {Vec3} xi
  12205. * @param {Vec3} xj
  12206. * @param {Quaternion} qi
  12207. * @param {Quaternion} qj
  12208. * @param {Body} bi
  12209. * @param {Body} bj
  12210. */
  12211. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.CONVEXPOLYHEDRON] =
  12212. Narrowphase.prototype.sphereConvex = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  12213. var v3pool = this.v3pool;
  12214. xi.vsub(xj,convex_to_sphere);
  12215. var normals = sj.faceNormals;
  12216. var faces = sj.faces;
  12217. var verts = sj.vertices;
  12218. var R = si.radius;
  12219. var penetrating_sides = [];
  12220. // if(convex_to_sphere.norm2() > si.boundingSphereRadius + sj.boundingSphereRadius){
  12221. // return;
  12222. // }
  12223. // Check corners
  12224. for(var i=0; i!==verts.length; i++){
  12225. var v = verts[i];
  12226. // World position of corner
  12227. var worldCorner = sphereConvex_worldCorner;
  12228. qj.vmult(v,worldCorner);
  12229. xj.vadd(worldCorner,worldCorner);
  12230. var sphere_to_corner = sphereConvex_sphereToCorner;
  12231. worldCorner.vsub(xi, sphere_to_corner);
  12232. if(sphere_to_corner.norm2() < R * R){
  12233. if(justTest){
  12234. return true;
  12235. }
  12236. found = true;
  12237. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  12238. r.ri.copy(sphere_to_corner);
  12239. r.ri.normalize();
  12240. r.ni.copy(r.ri);
  12241. r.ri.mult(R,r.ri);
  12242. worldCorner.vsub(xj,r.rj);
  12243. // Should be relative to the body.
  12244. r.ri.vadd(xi, r.ri);
  12245. r.ri.vsub(bi.position, r.ri);
  12246. // Should be relative to the body.
  12247. r.rj.vadd(xj, r.rj);
  12248. r.rj.vsub(bj.position, r.rj);
  12249. this.result.push(r);
  12250. this.createFrictionEquationsFromContact(r, this.frictionResult);
  12251. return;
  12252. }
  12253. }
  12254. // Check side (plane) intersections
  12255. var found = false;
  12256. for(var i=0, nfaces=faces.length; i!==nfaces && found===false; i++){
  12257. var normal = normals[i];
  12258. var face = faces[i];
  12259. // Get world-transformed normal of the face
  12260. var worldNormal = sphereConvex_worldNormal;
  12261. qj.vmult(normal,worldNormal);
  12262. // Get a world vertex from the face
  12263. var worldPoint = sphereConvex_worldPoint;
  12264. qj.vmult(verts[face[0]],worldPoint);
  12265. worldPoint.vadd(xj,worldPoint);
  12266. // Get a point on the sphere, closest to the face normal
  12267. var worldSpherePointClosestToPlane = sphereConvex_worldSpherePointClosestToPlane;
  12268. worldNormal.mult(-R, worldSpherePointClosestToPlane);
  12269. xi.vadd(worldSpherePointClosestToPlane, worldSpherePointClosestToPlane);
  12270. // Vector from a face point to the closest point on the sphere
  12271. var penetrationVec = sphereConvex_penetrationVec;
  12272. worldSpherePointClosestToPlane.vsub(worldPoint,penetrationVec);
  12273. // The penetration. Negative value means overlap.
  12274. var penetration = penetrationVec.dot(worldNormal);
  12275. var worldPointToSphere = sphereConvex_sphereToWorldPoint;
  12276. xi.vsub(worldPoint, worldPointToSphere);
  12277. if(penetration < 0 && worldPointToSphere.dot(worldNormal)>0){
  12278. // Intersects plane. Now check if the sphere is inside the face polygon
  12279. var faceVerts = []; // Face vertices, in world coords
  12280. for(var j=0, Nverts=face.length; j!==Nverts; j++){
  12281. var worldVertex = v3pool.get();
  12282. qj.vmult(verts[face[j]], worldVertex);
  12283. xj.vadd(worldVertex,worldVertex);
  12284. faceVerts.push(worldVertex);
  12285. }
  12286. if(pointInPolygon(faceVerts,worldNormal,xi)){ // Is the sphere center in the face polygon?
  12287. if(justTest){
  12288. return true;
  12289. }
  12290. found = true;
  12291. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  12292. worldNormal.mult(-R, r.ri); // Contact offset, from sphere center to contact
  12293. worldNormal.negate(r.ni); // Normal pointing out of sphere
  12294. var penetrationVec2 = v3pool.get();
  12295. worldNormal.mult(-penetration, penetrationVec2);
  12296. var penetrationSpherePoint = v3pool.get();
  12297. worldNormal.mult(-R, penetrationSpherePoint);
  12298. //xi.vsub(xj).vadd(penetrationSpherePoint).vadd(penetrationVec2 , r.rj);
  12299. xi.vsub(xj,r.rj);
  12300. r.rj.vadd(penetrationSpherePoint,r.rj);
  12301. r.rj.vadd(penetrationVec2 , r.rj);
  12302. // Should be relative to the body.
  12303. r.rj.vadd(xj, r.rj);
  12304. r.rj.vsub(bj.position, r.rj);
  12305. // Should be relative to the body.
  12306. r.ri.vadd(xi, r.ri);
  12307. r.ri.vsub(bi.position, r.ri);
  12308. v3pool.release(penetrationVec2);
  12309. v3pool.release(penetrationSpherePoint);
  12310. this.result.push(r);
  12311. this.createFrictionEquationsFromContact(r, this.frictionResult);
  12312. // Release world vertices
  12313. for(var j=0, Nfaceverts=faceVerts.length; j!==Nfaceverts; j++){
  12314. v3pool.release(faceVerts[j]);
  12315. }
  12316. return; // We only expect *one* face contact
  12317. } else {
  12318. // Edge?
  12319. for(var j=0; j!==face.length; j++){
  12320. // Get two world transformed vertices
  12321. var v1 = v3pool.get();
  12322. var v2 = v3pool.get();
  12323. qj.vmult(verts[face[(j+1)%face.length]], v1);
  12324. qj.vmult(verts[face[(j+2)%face.length]], v2);
  12325. xj.vadd(v1, v1);
  12326. xj.vadd(v2, v2);
  12327. // Construct edge vector
  12328. var edge = sphereConvex_edge;
  12329. v2.vsub(v1,edge);
  12330. // Construct the same vector, but normalized
  12331. var edgeUnit = sphereConvex_edgeUnit;
  12332. edge.unit(edgeUnit);
  12333. // p is xi projected onto the edge
  12334. var p = v3pool.get();
  12335. var v1_to_xi = v3pool.get();
  12336. xi.vsub(v1, v1_to_xi);
  12337. var dot = v1_to_xi.dot(edgeUnit);
  12338. edgeUnit.mult(dot, p);
  12339. p.vadd(v1, p);
  12340. // Compute a vector from p to the center of the sphere
  12341. var xi_to_p = v3pool.get();
  12342. p.vsub(xi, xi_to_p);
  12343. // Collision if the edge-sphere distance is less than the radius
  12344. // AND if p is in between v1 and v2
  12345. if(dot > 0 && dot*dot<edge.norm2() && xi_to_p.norm2() < R*R){ // Collision if the edge-sphere distance is less than the radius
  12346. // Edge contact!
  12347. if(justTest){
  12348. return true;
  12349. }
  12350. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  12351. p.vsub(xj,r.rj);
  12352. p.vsub(xi,r.ni);
  12353. r.ni.normalize();
  12354. r.ni.mult(R,r.ri);
  12355. // Should be relative to the body.
  12356. r.rj.vadd(xj, r.rj);
  12357. r.rj.vsub(bj.position, r.rj);
  12358. // Should be relative to the body.
  12359. r.ri.vadd(xi, r.ri);
  12360. r.ri.vsub(bi.position, r.ri);
  12361. this.result.push(r);
  12362. this.createFrictionEquationsFromContact(r, this.frictionResult);
  12363. // Release world vertices
  12364. for(var j=0, Nfaceverts=faceVerts.length; j!==Nfaceverts; j++){
  12365. v3pool.release(faceVerts[j]);
  12366. }
  12367. v3pool.release(v1);
  12368. v3pool.release(v2);
  12369. v3pool.release(p);
  12370. v3pool.release(xi_to_p);
  12371. v3pool.release(v1_to_xi);
  12372. return;
  12373. }
  12374. v3pool.release(v1);
  12375. v3pool.release(v2);
  12376. v3pool.release(p);
  12377. v3pool.release(xi_to_p);
  12378. v3pool.release(v1_to_xi);
  12379. }
  12380. }
  12381. // Release world vertices
  12382. for(var j=0, Nfaceverts=faceVerts.length; j!==Nfaceverts; j++){
  12383. v3pool.release(faceVerts[j]);
  12384. }
  12385. }
  12386. }
  12387. };
  12388. var planeBox_normal = new Vec3();
  12389. var plane_to_corner = new Vec3();
  12390. /**
  12391. * @method planeBox
  12392. * @param {Array} result
  12393. * @param {Shape} si
  12394. * @param {Shape} sj
  12395. * @param {Vec3} xi
  12396. * @param {Vec3} xj
  12397. * @param {Quaternion} qi
  12398. * @param {Quaternion} qj
  12399. * @param {Body} bi
  12400. * @param {Body} bj
  12401. */
  12402. Narrowphase.prototype[Shape.types.PLANE | Shape.types.BOX] =
  12403. Narrowphase.prototype.planeBox = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  12404. sj.convexPolyhedronRepresentation.material = sj.material;
  12405. sj.convexPolyhedronRepresentation.collisionResponse = sj.collisionResponse;
  12406. sj.convexPolyhedronRepresentation.id = sj.id;
  12407. return this.planeConvex(si,sj.convexPolyhedronRepresentation,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  12408. };
  12409. var planeConvex_v = new Vec3();
  12410. var planeConvex_normal = new Vec3();
  12411. var planeConvex_relpos = new Vec3();
  12412. var planeConvex_projected = new Vec3();
  12413. /**
  12414. * @method planeConvex
  12415. * @param {Shape} si
  12416. * @param {Shape} sj
  12417. * @param {Vec3} xi
  12418. * @param {Vec3} xj
  12419. * @param {Quaternion} qi
  12420. * @param {Quaternion} qj
  12421. * @param {Body} bi
  12422. * @param {Body} bj
  12423. */
  12424. Narrowphase.prototype[Shape.types.PLANE | Shape.types.CONVEXPOLYHEDRON] =
  12425. Narrowphase.prototype.planeConvex = function(
  12426. planeShape,
  12427. convexShape,
  12428. planePosition,
  12429. convexPosition,
  12430. planeQuat,
  12431. convexQuat,
  12432. planeBody,
  12433. convexBody,
  12434. si,
  12435. sj,
  12436. justTest
  12437. ){
  12438. // Simply return the points behind the plane.
  12439. var worldVertex = planeConvex_v,
  12440. worldNormal = planeConvex_normal;
  12441. worldNormal.set(0,0,1);
  12442. planeQuat.vmult(worldNormal,worldNormal); // Turn normal according to plane orientation
  12443. var numContacts = 0;
  12444. var relpos = planeConvex_relpos;
  12445. for(var i = 0; i !== convexShape.vertices.length; i++){
  12446. // Get world convex vertex
  12447. worldVertex.copy(convexShape.vertices[i]);
  12448. convexQuat.vmult(worldVertex, worldVertex);
  12449. convexPosition.vadd(worldVertex, worldVertex);
  12450. worldVertex.vsub(planePosition, relpos);
  12451. var dot = worldNormal.dot(relpos);
  12452. if(dot <= 0.0){
  12453. if(justTest){
  12454. return true;
  12455. }
  12456. var r = this.createContactEquation(planeBody, convexBody, planeShape, convexShape, si, sj);
  12457. // Get vertex position projected on plane
  12458. var projected = planeConvex_projected;
  12459. worldNormal.mult(worldNormal.dot(relpos),projected);
  12460. worldVertex.vsub(projected, projected);
  12461. projected.vsub(planePosition, r.ri); // From plane to vertex projected on plane
  12462. r.ni.copy(worldNormal); // Contact normal is the plane normal out from plane
  12463. // rj is now just the vector from the convex center to the vertex
  12464. worldVertex.vsub(convexPosition, r.rj);
  12465. // Make it relative to the body
  12466. r.ri.vadd(planePosition, r.ri);
  12467. r.ri.vsub(planeBody.position, r.ri);
  12468. r.rj.vadd(convexPosition, r.rj);
  12469. r.rj.vsub(convexBody.position, r.rj);
  12470. this.result.push(r);
  12471. numContacts++;
  12472. if(!this.enableFrictionReduction){
  12473. this.createFrictionEquationsFromContact(r, this.frictionResult);
  12474. }
  12475. }
  12476. }
  12477. if(this.enableFrictionReduction && numContacts){
  12478. this.createFrictionFromAverage(numContacts);
  12479. }
  12480. };
  12481. var convexConvex_sepAxis = new Vec3();
  12482. var convexConvex_q = new Vec3();
  12483. /**
  12484. * @method convexConvex
  12485. * @param {Shape} si
  12486. * @param {Shape} sj
  12487. * @param {Vec3} xi
  12488. * @param {Vec3} xj
  12489. * @param {Quaternion} qi
  12490. * @param {Quaternion} qj
  12491. * @param {Body} bi
  12492. * @param {Body} bj
  12493. */
  12494. Narrowphase.prototype[Shape.types.CONVEXPOLYHEDRON] =
  12495. Narrowphase.prototype.convexConvex = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest,faceListA,faceListB){
  12496. var sepAxis = convexConvex_sepAxis;
  12497. if(xi.distanceTo(xj) > si.boundingSphereRadius + sj.boundingSphereRadius){
  12498. return;
  12499. }
  12500. if(si.findSeparatingAxis(sj,xi,qi,xj,qj,sepAxis,faceListA,faceListB)){
  12501. var res = [];
  12502. var q = convexConvex_q;
  12503. si.clipAgainstHull(xi,qi,sj,xj,qj,sepAxis,-100,100,res);
  12504. var numContacts = 0;
  12505. for(var j = 0; j !== res.length; j++){
  12506. if(justTest){
  12507. return true;
  12508. }
  12509. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj),
  12510. ri = r.ri,
  12511. rj = r.rj;
  12512. sepAxis.negate(r.ni);
  12513. res[j].normal.negate(q);
  12514. q.mult(res[j].depth, q);
  12515. res[j].point.vadd(q, ri);
  12516. rj.copy(res[j].point);
  12517. // Contact points are in world coordinates. Transform back to relative
  12518. ri.vsub(xi,ri);
  12519. rj.vsub(xj,rj);
  12520. // Make relative to bodies
  12521. ri.vadd(xi, ri);
  12522. ri.vsub(bi.position, ri);
  12523. rj.vadd(xj, rj);
  12524. rj.vsub(bj.position, rj);
  12525. this.result.push(r);
  12526. numContacts++;
  12527. if(!this.enableFrictionReduction){
  12528. this.createFrictionEquationsFromContact(r, this.frictionResult);
  12529. }
  12530. }
  12531. if(this.enableFrictionReduction && numContacts){
  12532. this.createFrictionFromAverage(numContacts);
  12533. }
  12534. }
  12535. };
  12536. /**
  12537. * @method convexTrimesh
  12538. * @param {Array} result
  12539. * @param {Shape} si
  12540. * @param {Shape} sj
  12541. * @param {Vec3} xi
  12542. * @param {Vec3} xj
  12543. * @param {Quaternion} qi
  12544. * @param {Quaternion} qj
  12545. * @param {Body} bi
  12546. * @param {Body} bj
  12547. */
  12548. // Narrowphase.prototype[Shape.types.CONVEXPOLYHEDRON | Shape.types.TRIMESH] =
  12549. // Narrowphase.prototype.convexTrimesh = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,faceListA,faceListB){
  12550. // var sepAxis = convexConvex_sepAxis;
  12551. // if(xi.distanceTo(xj) > si.boundingSphereRadius + sj.boundingSphereRadius){
  12552. // return;
  12553. // }
  12554. // // Construct a temp hull for each triangle
  12555. // var hullB = new ConvexPolyhedron();
  12556. // hullB.faces = [[0,1,2]];
  12557. // var va = new Vec3();
  12558. // var vb = new Vec3();
  12559. // var vc = new Vec3();
  12560. // hullB.vertices = [
  12561. // va,
  12562. // vb,
  12563. // vc
  12564. // ];
  12565. // for (var i = 0; i < sj.indices.length / 3; i++) {
  12566. // var triangleNormal = new Vec3();
  12567. // sj.getNormal(i, triangleNormal);
  12568. // hullB.faceNormals = [triangleNormal];
  12569. // sj.getTriangleVertices(i, va, vb, vc);
  12570. // var d = si.testSepAxis(triangleNormal, hullB, xi, qi, xj, qj);
  12571. // if(!d){
  12572. // triangleNormal.scale(-1, triangleNormal);
  12573. // d = si.testSepAxis(triangleNormal, hullB, xi, qi, xj, qj);
  12574. // if(!d){
  12575. // continue;
  12576. // }
  12577. // }
  12578. // var res = [];
  12579. // var q = convexConvex_q;
  12580. // si.clipAgainstHull(xi,qi,hullB,xj,qj,triangleNormal,-100,100,res);
  12581. // for(var j = 0; j !== res.length; j++){
  12582. // var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj),
  12583. // ri = r.ri,
  12584. // rj = r.rj;
  12585. // r.ni.copy(triangleNormal);
  12586. // r.ni.negate(r.ni);
  12587. // res[j].normal.negate(q);
  12588. // q.mult(res[j].depth, q);
  12589. // res[j].point.vadd(q, ri);
  12590. // rj.copy(res[j].point);
  12591. // // Contact points are in world coordinates. Transform back to relative
  12592. // ri.vsub(xi,ri);
  12593. // rj.vsub(xj,rj);
  12594. // // Make relative to bodies
  12595. // ri.vadd(xi, ri);
  12596. // ri.vsub(bi.position, ri);
  12597. // rj.vadd(xj, rj);
  12598. // rj.vsub(bj.position, rj);
  12599. // result.push(r);
  12600. // }
  12601. // }
  12602. // };
  12603. var particlePlane_normal = new Vec3();
  12604. var particlePlane_relpos = new Vec3();
  12605. var particlePlane_projected = new Vec3();
  12606. /**
  12607. * @method particlePlane
  12608. * @param {Array} result
  12609. * @param {Shape} si
  12610. * @param {Shape} sj
  12611. * @param {Vec3} xi
  12612. * @param {Vec3} xj
  12613. * @param {Quaternion} qi
  12614. * @param {Quaternion} qj
  12615. * @param {Body} bi
  12616. * @param {Body} bj
  12617. */
  12618. Narrowphase.prototype[Shape.types.PLANE | Shape.types.PARTICLE] =
  12619. Narrowphase.prototype.planeParticle = function(sj,si,xj,xi,qj,qi,bj,bi,rsi,rsj,justTest){
  12620. var normal = particlePlane_normal;
  12621. normal.set(0,0,1);
  12622. bj.quaternion.vmult(normal,normal); // Turn normal according to plane orientation
  12623. var relpos = particlePlane_relpos;
  12624. xi.vsub(bj.position,relpos);
  12625. var dot = normal.dot(relpos);
  12626. if(dot <= 0.0){
  12627. if(justTest){
  12628. return true;
  12629. }
  12630. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  12631. r.ni.copy(normal); // Contact normal is the plane normal
  12632. r.ni.negate(r.ni);
  12633. r.ri.set(0,0,0); // Center of particle
  12634. // Get particle position projected on plane
  12635. var projected = particlePlane_projected;
  12636. normal.mult(normal.dot(xi),projected);
  12637. xi.vsub(projected,projected);
  12638. //projected.vadd(bj.position,projected);
  12639. // rj is now the projected world position minus plane position
  12640. r.rj.copy(projected);
  12641. this.result.push(r);
  12642. this.createFrictionEquationsFromContact(r, this.frictionResult);
  12643. }
  12644. };
  12645. var particleSphere_normal = new Vec3();
  12646. /**
  12647. * @method particleSphere
  12648. * @param {Array} result
  12649. * @param {Shape} si
  12650. * @param {Shape} sj
  12651. * @param {Vec3} xi
  12652. * @param {Vec3} xj
  12653. * @param {Quaternion} qi
  12654. * @param {Quaternion} qj
  12655. * @param {Body} bi
  12656. * @param {Body} bj
  12657. */
  12658. Narrowphase.prototype[Shape.types.PARTICLE | Shape.types.SPHERE] =
  12659. Narrowphase.prototype.sphereParticle = function(sj,si,xj,xi,qj,qi,bj,bi,rsi,rsj,justTest){
  12660. // The normal is the unit vector from sphere center to particle center
  12661. var normal = particleSphere_normal;
  12662. normal.set(0,0,1);
  12663. xi.vsub(xj,normal);
  12664. var lengthSquared = normal.norm2();
  12665. if(lengthSquared <= sj.radius * sj.radius){
  12666. if(justTest){
  12667. return true;
  12668. }
  12669. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  12670. normal.normalize();
  12671. r.rj.copy(normal);
  12672. r.rj.mult(sj.radius,r.rj);
  12673. r.ni.copy(normal); // Contact normal
  12674. r.ni.negate(r.ni);
  12675. r.ri.set(0,0,0); // Center of particle
  12676. this.result.push(r);
  12677. this.createFrictionEquationsFromContact(r, this.frictionResult);
  12678. }
  12679. };
  12680. // WIP
  12681. var cqj = new Quaternion();
  12682. var convexParticle_local = new Vec3();
  12683. var convexParticle_normal = new Vec3();
  12684. var convexParticle_penetratedFaceNormal = new Vec3();
  12685. var convexParticle_vertexToParticle = new Vec3();
  12686. var convexParticle_worldPenetrationVec = new Vec3();
  12687. /**
  12688. * @method convexParticle
  12689. * @param {Array} result
  12690. * @param {Shape} si
  12691. * @param {Shape} sj
  12692. * @param {Vec3} xi
  12693. * @param {Vec3} xj
  12694. * @param {Quaternion} qi
  12695. * @param {Quaternion} qj
  12696. * @param {Body} bi
  12697. * @param {Body} bj
  12698. */
  12699. Narrowphase.prototype[Shape.types.PARTICLE | Shape.types.CONVEXPOLYHEDRON] =
  12700. Narrowphase.prototype.convexParticle = function(sj,si,xj,xi,qj,qi,bj,bi,rsi,rsj,justTest){
  12701. var penetratedFaceIndex = -1;
  12702. var penetratedFaceNormal = convexParticle_penetratedFaceNormal;
  12703. var worldPenetrationVec = convexParticle_worldPenetrationVec;
  12704. var minPenetration = null;
  12705. var numDetectedFaces = 0;
  12706. // Convert particle position xi to local coords in the convex
  12707. var local = convexParticle_local;
  12708. local.copy(xi);
  12709. local.vsub(xj,local); // Convert position to relative the convex origin
  12710. qj.conjugate(cqj);
  12711. cqj.vmult(local,local);
  12712. if(sj.pointIsInside(local)){
  12713. if(sj.worldVerticesNeedsUpdate){
  12714. sj.computeWorldVertices(xj,qj);
  12715. }
  12716. if(sj.worldFaceNormalsNeedsUpdate){
  12717. sj.computeWorldFaceNormals(qj);
  12718. }
  12719. // For each world polygon in the polyhedra
  12720. for(var i=0,nfaces=sj.faces.length; i!==nfaces; i++){
  12721. // Construct world face vertices
  12722. var verts = [ sj.worldVertices[ sj.faces[i][0] ] ];
  12723. var normal = sj.worldFaceNormals[i];
  12724. // Check how much the particle penetrates the polygon plane.
  12725. xi.vsub(verts[0],convexParticle_vertexToParticle);
  12726. var penetration = -normal.dot(convexParticle_vertexToParticle);
  12727. if(minPenetration===null || Math.abs(penetration)<Math.abs(minPenetration)){
  12728. if(justTest){
  12729. return true;
  12730. }
  12731. minPenetration = penetration;
  12732. penetratedFaceIndex = i;
  12733. penetratedFaceNormal.copy(normal);
  12734. numDetectedFaces++;
  12735. }
  12736. }
  12737. if(penetratedFaceIndex!==-1){
  12738. // Setup contact
  12739. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  12740. penetratedFaceNormal.mult(minPenetration, worldPenetrationVec);
  12741. // rj is the particle position projected to the face
  12742. worldPenetrationVec.vadd(xi,worldPenetrationVec);
  12743. worldPenetrationVec.vsub(xj,worldPenetrationVec);
  12744. r.rj.copy(worldPenetrationVec);
  12745. //var projectedToFace = xi.vsub(xj).vadd(worldPenetrationVec);
  12746. //projectedToFace.copy(r.rj);
  12747. //qj.vmult(r.rj,r.rj);
  12748. penetratedFaceNormal.negate( r.ni ); // Contact normal
  12749. r.ri.set(0,0,0); // Center of particle
  12750. var ri = r.ri,
  12751. rj = r.rj;
  12752. // Make relative to bodies
  12753. ri.vadd(xi, ri);
  12754. ri.vsub(bi.position, ri);
  12755. rj.vadd(xj, rj);
  12756. rj.vsub(bj.position, rj);
  12757. this.result.push(r);
  12758. this.createFrictionEquationsFromContact(r, this.frictionResult);
  12759. } else {
  12760. console.warn("Point found inside convex, but did not find penetrating face!");
  12761. }
  12762. }
  12763. };
  12764. Narrowphase.prototype[Shape.types.BOX | Shape.types.HEIGHTFIELD] =
  12765. Narrowphase.prototype.boxHeightfield = function (si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  12766. si.convexPolyhedronRepresentation.material = si.material;
  12767. si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
  12768. return this.convexHeightfield(si.convexPolyhedronRepresentation,sj,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  12769. };
  12770. var convexHeightfield_tmp1 = new Vec3();
  12771. var convexHeightfield_tmp2 = new Vec3();
  12772. var convexHeightfield_faceList = [0];
  12773. /**
  12774. * @method convexHeightfield
  12775. */
  12776. Narrowphase.prototype[Shape.types.CONVEXPOLYHEDRON | Shape.types.HEIGHTFIELD] =
  12777. Narrowphase.prototype.convexHeightfield = function (
  12778. convexShape,
  12779. hfShape,
  12780. convexPos,
  12781. hfPos,
  12782. convexQuat,
  12783. hfQuat,
  12784. convexBody,
  12785. hfBody,
  12786. rsi,
  12787. rsj,
  12788. justTest
  12789. ){
  12790. var data = hfShape.data,
  12791. w = hfShape.elementSize,
  12792. radius = convexShape.boundingSphereRadius,
  12793. worldPillarOffset = convexHeightfield_tmp2,
  12794. faceList = convexHeightfield_faceList;
  12795. // Get sphere position to heightfield local!
  12796. var localConvexPos = convexHeightfield_tmp1;
  12797. Transform.pointToLocalFrame(hfPos, hfQuat, convexPos, localConvexPos);
  12798. // Get the index of the data points to test against
  12799. var iMinX = Math.floor((localConvexPos.x - radius) / w) - 1,
  12800. iMaxX = Math.ceil((localConvexPos.x + radius) / w) + 1,
  12801. iMinY = Math.floor((localConvexPos.y - radius) / w) - 1,
  12802. iMaxY = Math.ceil((localConvexPos.y + radius) / w) + 1;
  12803. // Bail out if we are out of the terrain
  12804. if(iMaxX < 0 || iMaxY < 0 || iMinX > data.length || iMinY > data[0].length){
  12805. return;
  12806. }
  12807. // Clamp index to edges
  12808. if(iMinX < 0){ iMinX = 0; }
  12809. if(iMaxX < 0){ iMaxX = 0; }
  12810. if(iMinY < 0){ iMinY = 0; }
  12811. if(iMaxY < 0){ iMaxY = 0; }
  12812. if(iMinX >= data.length){ iMinX = data.length - 1; }
  12813. if(iMaxX >= data.length){ iMaxX = data.length - 1; }
  12814. if(iMaxY >= data[0].length){ iMaxY = data[0].length - 1; }
  12815. if(iMinY >= data[0].length){ iMinY = data[0].length - 1; }
  12816. var minMax = [];
  12817. hfShape.getRectMinMax(iMinX, iMinY, iMaxX, iMaxY, minMax);
  12818. var min = minMax[0];
  12819. var max = minMax[1];
  12820. // Bail out if we're cant touch the bounding height box
  12821. if(localConvexPos.z - radius > max || localConvexPos.z + radius < min){
  12822. return;
  12823. }
  12824. for(var i = iMinX; i < iMaxX; i++){
  12825. for(var j = iMinY; j < iMaxY; j++){
  12826. var intersecting = false;
  12827. // Lower triangle
  12828. hfShape.getConvexTrianglePillar(i, j, false);
  12829. Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
  12830. if (convexPos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + convexShape.boundingSphereRadius) {
  12831. intersecting = this.convexConvex(convexShape, hfShape.pillarConvex, convexPos, worldPillarOffset, convexQuat, hfQuat, convexBody, hfBody, null, null, justTest, faceList, null);
  12832. }
  12833. if(justTest && intersecting){
  12834. return true;
  12835. }
  12836. // Upper triangle
  12837. hfShape.getConvexTrianglePillar(i, j, true);
  12838. Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
  12839. if (convexPos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + convexShape.boundingSphereRadius) {
  12840. intersecting = this.convexConvex(convexShape, hfShape.pillarConvex, convexPos, worldPillarOffset, convexQuat, hfQuat, convexBody, hfBody, null, null, justTest, faceList, null);
  12841. }
  12842. if(justTest && intersecting){
  12843. return true;
  12844. }
  12845. }
  12846. }
  12847. };
  12848. var sphereHeightfield_tmp1 = new Vec3();
  12849. var sphereHeightfield_tmp2 = new Vec3();
  12850. /**
  12851. * @method sphereHeightfield
  12852. */
  12853. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.HEIGHTFIELD] =
  12854. Narrowphase.prototype.sphereHeightfield = function (
  12855. sphereShape,
  12856. hfShape,
  12857. spherePos,
  12858. hfPos,
  12859. sphereQuat,
  12860. hfQuat,
  12861. sphereBody,
  12862. hfBody,
  12863. rsi,
  12864. rsj,
  12865. justTest
  12866. ){
  12867. var data = hfShape.data,
  12868. radius = sphereShape.radius,
  12869. w = hfShape.elementSize,
  12870. worldPillarOffset = sphereHeightfield_tmp2;
  12871. // Get sphere position to heightfield local!
  12872. var localSpherePos = sphereHeightfield_tmp1;
  12873. Transform.pointToLocalFrame(hfPos, hfQuat, spherePos, localSpherePos);
  12874. // Get the index of the data points to test against
  12875. var iMinX = Math.floor((localSpherePos.x - radius) / w) - 1,
  12876. iMaxX = Math.ceil((localSpherePos.x + radius) / w) + 1,
  12877. iMinY = Math.floor((localSpherePos.y - radius) / w) - 1,
  12878. iMaxY = Math.ceil((localSpherePos.y + radius) / w) + 1;
  12879. // Bail out if we are out of the terrain
  12880. if(iMaxX < 0 || iMaxY < 0 || iMinX > data.length || iMaxY > data[0].length){
  12881. return;
  12882. }
  12883. // Clamp index to edges
  12884. if(iMinX < 0){ iMinX = 0; }
  12885. if(iMaxX < 0){ iMaxX = 0; }
  12886. if(iMinY < 0){ iMinY = 0; }
  12887. if(iMaxY < 0){ iMaxY = 0; }
  12888. if(iMinX >= data.length){ iMinX = data.length - 1; }
  12889. if(iMaxX >= data.length){ iMaxX = data.length - 1; }
  12890. if(iMaxY >= data[0].length){ iMaxY = data[0].length - 1; }
  12891. if(iMinY >= data[0].length){ iMinY = data[0].length - 1; }
  12892. var minMax = [];
  12893. hfShape.getRectMinMax(iMinX, iMinY, iMaxX, iMaxY, minMax);
  12894. var min = minMax[0];
  12895. var max = minMax[1];
  12896. // Bail out if we're cant touch the bounding height box
  12897. if(localSpherePos.z - radius > max || localSpherePos.z + radius < min){
  12898. return;
  12899. }
  12900. var result = this.result;
  12901. for(var i = iMinX; i < iMaxX; i++){
  12902. for(var j = iMinY; j < iMaxY; j++){
  12903. var numContactsBefore = result.length;
  12904. var intersecting = false;
  12905. // Lower triangle
  12906. hfShape.getConvexTrianglePillar(i, j, false);
  12907. Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
  12908. if (spherePos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + sphereShape.boundingSphereRadius) {
  12909. intersecting = this.sphereConvex(sphereShape, hfShape.pillarConvex, spherePos, worldPillarOffset, sphereQuat, hfQuat, sphereBody, hfBody, sphereShape, hfShape, justTest);
  12910. }
  12911. if(justTest && intersecting){
  12912. return true;
  12913. }
  12914. // Upper triangle
  12915. hfShape.getConvexTrianglePillar(i, j, true);
  12916. Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
  12917. if (spherePos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + sphereShape.boundingSphereRadius) {
  12918. intersecting = this.sphereConvex(sphereShape, hfShape.pillarConvex, spherePos, worldPillarOffset, sphereQuat, hfQuat, sphereBody, hfBody, sphereShape, hfShape, justTest);
  12919. }
  12920. if(justTest && intersecting){
  12921. return true;
  12922. }
  12923. var numContacts = result.length - numContactsBefore;
  12924. if(numContacts > 2){
  12925. return;
  12926. }
  12927. /*
  12928. // Skip all but 1
  12929. for (var k = 0; k < numContacts - 1; k++) {
  12930. result.pop();
  12931. }
  12932. */
  12933. }
  12934. }
  12935. };
  12936. },{"../collision/AABB":18,"../collision/Ray":25,"../equations/ContactEquation":35,"../equations/FrictionEquation":37,"../math/Quaternion":44,"../math/Transform":45,"../math/Vec3":46,"../objects/Body":47,"../shapes/ConvexPolyhedron":54,"../shapes/Shape":59,"../solver/Solver":63,"../utils/Vec3Pool":70}],72:[function(require,module,exports){
  12937. /* global performance */
  12938. module.exports = World;
  12939. var Shape = require('../shapes/Shape');
  12940. var Vec3 = require('../math/Vec3');
  12941. var Quaternion = require('../math/Quaternion');
  12942. var GSSolver = require('../solver/GSSolver');
  12943. var ContactEquation = require('../equations/ContactEquation');
  12944. var FrictionEquation = require('../equations/FrictionEquation');
  12945. var Narrowphase = require('./Narrowphase');
  12946. var EventTarget = require('../utils/EventTarget');
  12947. var ArrayCollisionMatrix = require('../collision/ArrayCollisionMatrix');
  12948. var OverlapKeeper = require('../collision/OverlapKeeper');
  12949. var Material = require('../material/Material');
  12950. var ContactMaterial = require('../material/ContactMaterial');
  12951. var Body = require('../objects/Body');
  12952. var TupleDictionary = require('../utils/TupleDictionary');
  12953. var RaycastResult = require('../collision/RaycastResult');
  12954. var AABB = require('../collision/AABB');
  12955. var Ray = require('../collision/Ray');
  12956. var NaiveBroadphase = require('../collision/NaiveBroadphase');
  12957. /**
  12958. * The physics world
  12959. * @class World
  12960. * @constructor
  12961. * @extends EventTarget
  12962. * @param {object} [options]
  12963. * @param {Vec3} [options.gravity]
  12964. * @param {boolean} [options.allowSleep]
  12965. * @param {Broadphase} [options.broadphase]
  12966. * @param {Solver} [options.solver]
  12967. * @param {boolean} [options.quatNormalizeFast]
  12968. * @param {number} [options.quatNormalizeSkip]
  12969. */
  12970. function World(options){
  12971. options = options || {};
  12972. EventTarget.apply(this);
  12973. /**
  12974. * Currently / last used timestep. Is set to -1 if not available. This value is updated before each internal step, which means that it is "fresh" inside event callbacks.
  12975. * @property {Number} dt
  12976. */
  12977. this.dt = -1;
  12978. /**
  12979. * Makes bodies go to sleep when they've been inactive
  12980. * @property allowSleep
  12981. * @type {Boolean}
  12982. * @default false
  12983. */
  12984. this.allowSleep = !!options.allowSleep;
  12985. /**
  12986. * All the current contacts (instances of ContactEquation) in the world.
  12987. * @property contacts
  12988. * @type {Array}
  12989. */
  12990. this.contacts = [];
  12991. this.frictionEquations = [];
  12992. /**
  12993. * How often to normalize quaternions. Set to 0 for every step, 1 for every second etc.. A larger value increases performance. If bodies tend to explode, set to a smaller value (zero to be sure nothing can go wrong).
  12994. * @property quatNormalizeSkip
  12995. * @type {Number}
  12996. * @default 0
  12997. */
  12998. this.quatNormalizeSkip = options.quatNormalizeSkip !== undefined ? options.quatNormalizeSkip : 0;
  12999. /**
  13000. * Set to true to use fast quaternion normalization. It is often enough accurate to use. If bodies tend to explode, set to false.
  13001. * @property quatNormalizeFast
  13002. * @type {Boolean}
  13003. * @see Quaternion.normalizeFast
  13004. * @see Quaternion.normalize
  13005. * @default false
  13006. */
  13007. this.quatNormalizeFast = options.quatNormalizeFast !== undefined ? options.quatNormalizeFast : false;
  13008. /**
  13009. * The wall-clock time since simulation start
  13010. * @property time
  13011. * @type {Number}
  13012. */
  13013. this.time = 0.0;
  13014. /**
  13015. * Number of timesteps taken since start
  13016. * @property stepnumber
  13017. * @type {Number}
  13018. */
  13019. this.stepnumber = 0;
  13020. /// Default and last timestep sizes
  13021. this.default_dt = 1/60;
  13022. this.nextId = 0;
  13023. /**
  13024. * @property gravity
  13025. * @type {Vec3}
  13026. */
  13027. this.gravity = new Vec3();
  13028. if(options.gravity){
  13029. this.gravity.copy(options.gravity);
  13030. }
  13031. /**
  13032. * The broadphase algorithm to use. Default is NaiveBroadphase
  13033. * @property broadphase
  13034. * @type {Broadphase}
  13035. */
  13036. this.broadphase = options.broadphase !== undefined ? options.broadphase : new NaiveBroadphase();
  13037. /**
  13038. * @property bodies
  13039. * @type {Array}
  13040. */
  13041. this.bodies = [];
  13042. /**
  13043. * The solver algorithm to use. Default is GSSolver
  13044. * @property solver
  13045. * @type {Solver}
  13046. */
  13047. this.solver = options.solver !== undefined ? options.solver : new GSSolver();
  13048. /**
  13049. * @property constraints
  13050. * @type {Array}
  13051. */
  13052. this.constraints = [];
  13053. /**
  13054. * @property narrowphase
  13055. * @type {Narrowphase}
  13056. */
  13057. this.narrowphase = new Narrowphase(this);
  13058. /**
  13059. * @property {ArrayCollisionMatrix} collisionMatrix
  13060. * @type {ArrayCollisionMatrix}
  13061. */
  13062. this.collisionMatrix = new ArrayCollisionMatrix();
  13063. /**
  13064. * CollisionMatrix from the previous step.
  13065. * @property {ArrayCollisionMatrix} collisionMatrixPrevious
  13066. * @type {ArrayCollisionMatrix}
  13067. */
  13068. this.collisionMatrixPrevious = new ArrayCollisionMatrix();
  13069. this.bodyOverlapKeeper = new OverlapKeeper();
  13070. this.shapeOverlapKeeper = new OverlapKeeper();
  13071. /**
  13072. * All added materials
  13073. * @property materials
  13074. * @type {Array}
  13075. */
  13076. this.materials = [];
  13077. /**
  13078. * @property contactmaterials
  13079. * @type {Array}
  13080. */
  13081. this.contactmaterials = [];
  13082. /**
  13083. * Used to look up a ContactMaterial given two instances of Material.
  13084. * @property {TupleDictionary} contactMaterialTable
  13085. */
  13086. this.contactMaterialTable = new TupleDictionary();
  13087. this.defaultMaterial = new Material("default");
  13088. /**
  13089. * This contact material is used if no suitable contactmaterial is found for a contact.
  13090. * @property defaultContactMaterial
  13091. * @type {ContactMaterial}
  13092. */
  13093. this.defaultContactMaterial = new ContactMaterial(this.defaultMaterial, this.defaultMaterial, { friction: 0.3, restitution: 0.0 });
  13094. /**
  13095. * @property doProfiling
  13096. * @type {Boolean}
  13097. */
  13098. this.doProfiling = false;
  13099. /**
  13100. * @property profile
  13101. * @type {Object}
  13102. */
  13103. this.profile = {
  13104. solve:0,
  13105. makeContactConstraints:0,
  13106. broadphase:0,
  13107. integrate:0,
  13108. narrowphase:0,
  13109. };
  13110. /**
  13111. * Time accumulator for interpolation. See http://gafferongames.com/game-physics/fix-your-timestep/
  13112. * @property {Number} accumulator
  13113. */
  13114. this.accumulator = 0;
  13115. /**
  13116. * @property subsystems
  13117. * @type {Array}
  13118. */
  13119. this.subsystems = [];
  13120. /**
  13121. * Dispatched after a body has been added to the world.
  13122. * @event addBody
  13123. * @param {Body} body The body that has been added to the world.
  13124. */
  13125. this.addBodyEvent = {
  13126. type:"addBody",
  13127. body : null
  13128. };
  13129. /**
  13130. * Dispatched after a body has been removed from the world.
  13131. * @event removeBody
  13132. * @param {Body} body The body that has been removed from the world.
  13133. */
  13134. this.removeBodyEvent = {
  13135. type:"removeBody",
  13136. body : null
  13137. };
  13138. this.idToBodyMap = {};
  13139. this.broadphase.setWorld(this);
  13140. }
  13141. World.prototype = new EventTarget();
  13142. // Temp stuff
  13143. var tmpAABB1 = new AABB();
  13144. var tmpArray1 = [];
  13145. var tmpRay = new Ray();
  13146. /**
  13147. * Get the contact material between materials m1 and m2
  13148. * @method getContactMaterial
  13149. * @param {Material} m1
  13150. * @param {Material} m2
  13151. * @return {ContactMaterial} The contact material if it was found.
  13152. */
  13153. World.prototype.getContactMaterial = function(m1,m2){
  13154. return this.contactMaterialTable.get(m1.id,m2.id); //this.contactmaterials[this.mats2cmat[i+j*this.materials.length]];
  13155. };
  13156. /**
  13157. * Get number of objects in the world.
  13158. * @method numObjects
  13159. * @return {Number}
  13160. * @deprecated
  13161. */
  13162. World.prototype.numObjects = function(){
  13163. return this.bodies.length;
  13164. };
  13165. /**
  13166. * Store old collision state info
  13167. * @method collisionMatrixTick
  13168. */
  13169. World.prototype.collisionMatrixTick = function(){
  13170. var temp = this.collisionMatrixPrevious;
  13171. this.collisionMatrixPrevious = this.collisionMatrix;
  13172. this.collisionMatrix = temp;
  13173. this.collisionMatrix.reset();
  13174. this.bodyOverlapKeeper.tick();
  13175. this.shapeOverlapKeeper.tick();
  13176. };
  13177. /**
  13178. * Add a rigid body to the simulation.
  13179. * @method add
  13180. * @param {Body} body
  13181. * @todo If the simulation has not yet started, why recrete and copy arrays for each body? Accumulate in dynamic arrays in this case.
  13182. * @todo Adding an array of bodies should be possible. This would save some loops too
  13183. * @deprecated Use .addBody instead
  13184. */
  13185. World.prototype.add = World.prototype.addBody = function(body){
  13186. if(this.bodies.indexOf(body) !== -1){
  13187. return;
  13188. }
  13189. body.index = this.bodies.length;
  13190. this.bodies.push(body);
  13191. body.world = this;
  13192. body.initPosition.copy(body.position);
  13193. body.initVelocity.copy(body.velocity);
  13194. body.timeLastSleepy = this.time;
  13195. if(body instanceof Body){
  13196. body.initAngularVelocity.copy(body.angularVelocity);
  13197. body.initQuaternion.copy(body.quaternion);
  13198. }
  13199. this.collisionMatrix.setNumObjects(this.bodies.length);
  13200. this.addBodyEvent.body = body;
  13201. this.idToBodyMap[body.id] = body;
  13202. this.dispatchEvent(this.addBodyEvent);
  13203. };
  13204. /**
  13205. * Add a constraint to the simulation.
  13206. * @method addConstraint
  13207. * @param {Constraint} c
  13208. */
  13209. World.prototype.addConstraint = function(c){
  13210. this.constraints.push(c);
  13211. };
  13212. /**
  13213. * Removes a constraint
  13214. * @method removeConstraint
  13215. * @param {Constraint} c
  13216. */
  13217. World.prototype.removeConstraint = function(c){
  13218. var idx = this.constraints.indexOf(c);
  13219. if(idx!==-1){
  13220. this.constraints.splice(idx,1);
  13221. }
  13222. };
  13223. /**
  13224. * Raycast test
  13225. * @method rayTest
  13226. * @param {Vec3} from
  13227. * @param {Vec3} to
  13228. * @param {RaycastResult} result
  13229. * @deprecated Use .raycastAll, .raycastClosest or .raycastAny instead.
  13230. */
  13231. World.prototype.rayTest = function(from, to, result){
  13232. if(result instanceof RaycastResult){
  13233. // Do raycastclosest
  13234. this.raycastClosest(from, to, {
  13235. skipBackfaces: true
  13236. }, result);
  13237. } else {
  13238. // Do raycastAll
  13239. this.raycastAll(from, to, {
  13240. skipBackfaces: true
  13241. }, result);
  13242. }
  13243. };
  13244. /**
  13245. * Ray cast against all bodies. The provided callback will be executed for each hit with a RaycastResult as single argument.
  13246. * @method raycastAll
  13247. * @param {Vec3} from
  13248. * @param {Vec3} to
  13249. * @param {Object} options
  13250. * @param {number} [options.collisionFilterMask=-1]
  13251. * @param {number} [options.collisionFilterGroup=-1]
  13252. * @param {boolean} [options.skipBackfaces=false]
  13253. * @param {boolean} [options.checkCollisionResponse=true]
  13254. * @param {Function} callback
  13255. * @return {boolean} True if any body was hit.
  13256. */
  13257. World.prototype.raycastAll = function(from, to, options, callback){
  13258. options.mode = Ray.ALL;
  13259. options.from = from;
  13260. options.to = to;
  13261. options.callback = callback;
  13262. return tmpRay.intersectWorld(this, options);
  13263. };
  13264. /**
  13265. * Ray cast, and stop at the first result. Note that the order is random - but the method is fast.
  13266. * @method raycastAny
  13267. * @param {Vec3} from
  13268. * @param {Vec3} to
  13269. * @param {Object} options
  13270. * @param {number} [options.collisionFilterMask=-1]
  13271. * @param {number} [options.collisionFilterGroup=-1]
  13272. * @param {boolean} [options.skipBackfaces=false]
  13273. * @param {boolean} [options.checkCollisionResponse=true]
  13274. * @param {RaycastResult} result
  13275. * @return {boolean} True if any body was hit.
  13276. */
  13277. World.prototype.raycastAny = function(from, to, options, result){
  13278. options.mode = Ray.ANY;
  13279. options.from = from;
  13280. options.to = to;
  13281. options.result = result;
  13282. return tmpRay.intersectWorld(this, options);
  13283. };
  13284. /**
  13285. * Ray cast, and return information of the closest hit.
  13286. * @method raycastClosest
  13287. * @param {Vec3} from
  13288. * @param {Vec3} to
  13289. * @param {Object} options
  13290. * @param {number} [options.collisionFilterMask=-1]
  13291. * @param {number} [options.collisionFilterGroup=-1]
  13292. * @param {boolean} [options.skipBackfaces=false]
  13293. * @param {boolean} [options.checkCollisionResponse=true]
  13294. * @param {RaycastResult} result
  13295. * @return {boolean} True if any body was hit.
  13296. */
  13297. World.prototype.raycastClosest = function(from, to, options, result){
  13298. options.mode = Ray.CLOSEST;
  13299. options.from = from;
  13300. options.to = to;
  13301. options.result = result;
  13302. return tmpRay.intersectWorld(this, options);
  13303. };
  13304. /**
  13305. * Remove a rigid body from the simulation.
  13306. * @method remove
  13307. * @param {Body} body
  13308. * @deprecated Use .removeBody instead
  13309. */
  13310. World.prototype.remove = function(body){
  13311. body.world = null;
  13312. var n = this.bodies.length - 1,
  13313. bodies = this.bodies,
  13314. idx = bodies.indexOf(body);
  13315. if(idx !== -1){
  13316. bodies.splice(idx, 1); // Todo: should use a garbage free method
  13317. // Recompute index
  13318. for(var i=0; i!==bodies.length; i++){
  13319. bodies[i].index = i;
  13320. }
  13321. this.collisionMatrix.setNumObjects(n);
  13322. this.removeBodyEvent.body = body;
  13323. delete this.idToBodyMap[body.id];
  13324. this.dispatchEvent(this.removeBodyEvent);
  13325. }
  13326. };
  13327. /**
  13328. * Remove a rigid body from the simulation.
  13329. * @method removeBody
  13330. * @param {Body} body
  13331. */
  13332. World.prototype.removeBody = World.prototype.remove;
  13333. World.prototype.getBodyById = function(id){
  13334. return this.idToBodyMap[id];
  13335. };
  13336. // TODO Make a faster map
  13337. World.prototype.getShapeById = function(id){
  13338. var bodies = this.bodies;
  13339. for(var i=0, bl = bodies.length; i<bl; i++){
  13340. var shapes = bodies[i].shapes;
  13341. for (var j = 0, sl = shapes.length; j < sl; j++) {
  13342. var shape = shapes[j];
  13343. if(shape.id === id){
  13344. return shape;
  13345. }
  13346. }
  13347. }
  13348. };
  13349. /**
  13350. * Adds a material to the World.
  13351. * @method addMaterial
  13352. * @param {Material} m
  13353. * @todo Necessary?
  13354. */
  13355. World.prototype.addMaterial = function(m){
  13356. this.materials.push(m);
  13357. };
  13358. /**
  13359. * Adds a contact material to the World
  13360. * @method addContactMaterial
  13361. * @param {ContactMaterial} cmat
  13362. */
  13363. World.prototype.addContactMaterial = function(cmat) {
  13364. // Add contact material
  13365. this.contactmaterials.push(cmat);
  13366. // Add current contact material to the material table
  13367. this.contactMaterialTable.set(cmat.materials[0].id,cmat.materials[1].id,cmat);
  13368. };
  13369. // performance.now()
  13370. if(typeof performance === 'undefined'){
  13371. performance = {};
  13372. }
  13373. if(!performance.now){
  13374. var nowOffset = Date.now();
  13375. if (performance.timing && performance.timing.navigationStart){
  13376. nowOffset = performance.timing.navigationStart;
  13377. }
  13378. performance.now = function(){
  13379. return Date.now() - nowOffset;
  13380. };
  13381. }
  13382. var step_tmp1 = new Vec3();
  13383. /**
  13384. * Step the physics world forward in time.
  13385. *
  13386. * There are two modes. The simple mode is fixed timestepping without interpolation. In this case you only use the first argument. The second case uses interpolation. In that you also provide the time since the function was last used, as well as the maximum fixed timesteps to take.
  13387. *
  13388. * @method step
  13389. * @param {Number} dt The fixed time step size to use.
  13390. * @param {Number} [timeSinceLastCalled] The time elapsed since the function was last called.
  13391. * @param {Number} [maxSubSteps=10] Maximum number of fixed steps to take per function call.
  13392. *
  13393. * @example
  13394. * // fixed timestepping without interpolation
  13395. * world.step(1/60);
  13396. *
  13397. * @see http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World
  13398. */
  13399. World.prototype.step = function(dt, timeSinceLastCalled, maxSubSteps){
  13400. maxSubSteps = maxSubSteps || 10;
  13401. timeSinceLastCalled = timeSinceLastCalled || 0;
  13402. if(timeSinceLastCalled === 0){ // Fixed, simple stepping
  13403. this.internalStep(dt);
  13404. // Increment time
  13405. this.time += dt;
  13406. } else {
  13407. this.accumulator += timeSinceLastCalled;
  13408. var substeps = 0;
  13409. while (this.accumulator >= dt && substeps < maxSubSteps) {
  13410. // Do fixed steps to catch up
  13411. this.internalStep(dt);
  13412. this.accumulator -= dt;
  13413. substeps++;
  13414. }
  13415. var t = (this.accumulator % dt) / dt;
  13416. for(var j=0; j !== this.bodies.length; j++){
  13417. var b = this.bodies[j];
  13418. b.previousPosition.lerp(b.position, t, b.interpolatedPosition);
  13419. b.previousQuaternion.slerp(b.quaternion, t, b.interpolatedQuaternion);
  13420. b.previousQuaternion.normalize();
  13421. }
  13422. this.time += timeSinceLastCalled;
  13423. }
  13424. };
  13425. var
  13426. /**
  13427. * Dispatched after the world has stepped forward in time.
  13428. * @event postStep
  13429. */
  13430. World_step_postStepEvent = {type:"postStep"}, // Reusable event objects to save memory
  13431. /**
  13432. * Dispatched before the world steps forward in time.
  13433. * @event preStep
  13434. */
  13435. World_step_preStepEvent = {type:"preStep"},
  13436. World_step_collideEvent = {type:Body.COLLIDE_EVENT_NAME, body:null, contact:null },
  13437. World_step_oldContacts = [], // Pools for unused objects
  13438. World_step_frictionEquationPool = [],
  13439. World_step_p1 = [], // Reusable arrays for collision pairs
  13440. World_step_p2 = [],
  13441. World_step_gvec = new Vec3(), // Temporary vectors and quats
  13442. World_step_vi = new Vec3(),
  13443. World_step_vj = new Vec3(),
  13444. World_step_wi = new Vec3(),
  13445. World_step_wj = new Vec3(),
  13446. World_step_t1 = new Vec3(),
  13447. World_step_t2 = new Vec3(),
  13448. World_step_rixn = new Vec3(),
  13449. World_step_rjxn = new Vec3(),
  13450. World_step_step_q = new Quaternion(),
  13451. World_step_step_w = new Quaternion(),
  13452. World_step_step_wq = new Quaternion(),
  13453. invI_tau_dt = new Vec3();
  13454. World.prototype.internalStep = function(dt){
  13455. this.dt = dt;
  13456. var world = this,
  13457. that = this,
  13458. contacts = this.contacts,
  13459. p1 = World_step_p1,
  13460. p2 = World_step_p2,
  13461. N = this.numObjects(),
  13462. bodies = this.bodies,
  13463. solver = this.solver,
  13464. gravity = this.gravity,
  13465. doProfiling = this.doProfiling,
  13466. profile = this.profile,
  13467. DYNAMIC = Body.DYNAMIC,
  13468. profilingStart,
  13469. constraints = this.constraints,
  13470. frictionEquationPool = World_step_frictionEquationPool,
  13471. gnorm = gravity.norm(),
  13472. gx = gravity.x,
  13473. gy = gravity.y,
  13474. gz = gravity.z,
  13475. i=0;
  13476. if(doProfiling){
  13477. profilingStart = performance.now();
  13478. }
  13479. // Add gravity to all objects
  13480. for(i=0; i!==N; i++){
  13481. var bi = bodies[i];
  13482. if(bi.type === DYNAMIC){ // Only for dynamic bodies
  13483. var f = bi.force, m = bi.mass;
  13484. f.x += m*gx;
  13485. f.y += m*gy;
  13486. f.z += m*gz;
  13487. }
  13488. }
  13489. // Update subsystems
  13490. for(var i=0, Nsubsystems=this.subsystems.length; i!==Nsubsystems; i++){
  13491. this.subsystems[i].update();
  13492. }
  13493. // Collision detection
  13494. if(doProfiling){ profilingStart = performance.now(); }
  13495. p1.length = 0; // Clean up pair arrays from last step
  13496. p2.length = 0;
  13497. this.broadphase.collisionPairs(this,p1,p2);
  13498. if(doProfiling){ profile.broadphase = performance.now() - profilingStart; }
  13499. // Remove constrained pairs with collideConnected == false
  13500. var Nconstraints = constraints.length;
  13501. for(i=0; i!==Nconstraints; i++){
  13502. var c = constraints[i];
  13503. if(!c.collideConnected){
  13504. for(var j = p1.length-1; j>=0; j-=1){
  13505. if( (c.bodyA === p1[j] && c.bodyB === p2[j]) ||
  13506. (c.bodyB === p1[j] && c.bodyA === p2[j])){
  13507. p1.splice(j, 1);
  13508. p2.splice(j, 1);
  13509. }
  13510. }
  13511. }
  13512. }
  13513. this.collisionMatrixTick();
  13514. // Generate contacts
  13515. if(doProfiling){ profilingStart = performance.now(); }
  13516. var oldcontacts = World_step_oldContacts;
  13517. var NoldContacts = contacts.length;
  13518. for(i=0; i!==NoldContacts; i++){
  13519. oldcontacts.push(contacts[i]);
  13520. }
  13521. contacts.length = 0;
  13522. // Transfer FrictionEquation from current list to the pool for reuse
  13523. var NoldFrictionEquations = this.frictionEquations.length;
  13524. for(i=0; i!==NoldFrictionEquations; i++){
  13525. frictionEquationPool.push(this.frictionEquations[i]);
  13526. }
  13527. this.frictionEquations.length = 0;
  13528. this.narrowphase.getContacts(
  13529. p1,
  13530. p2,
  13531. this,
  13532. contacts,
  13533. oldcontacts, // To be reused
  13534. this.frictionEquations,
  13535. frictionEquationPool
  13536. );
  13537. if(doProfiling){
  13538. profile.narrowphase = performance.now() - profilingStart;
  13539. }
  13540. // Loop over all collisions
  13541. if(doProfiling){
  13542. profilingStart = performance.now();
  13543. }
  13544. // Add all friction eqs
  13545. for (var i = 0; i < this.frictionEquations.length; i++) {
  13546. solver.addEquation(this.frictionEquations[i]);
  13547. }
  13548. var ncontacts = contacts.length;
  13549. for(var k=0; k!==ncontacts; k++){
  13550. // Current contact
  13551. var c = contacts[k];
  13552. // Get current collision indeces
  13553. var bi = c.bi,
  13554. bj = c.bj,
  13555. si = c.si,
  13556. sj = c.sj;
  13557. // Get collision properties
  13558. var cm;
  13559. if(bi.material && bj.material){
  13560. cm = this.getContactMaterial(bi.material,bj.material) || this.defaultContactMaterial;
  13561. } else {
  13562. cm = this.defaultContactMaterial;
  13563. }
  13564. // c.enabled = bi.collisionResponse && bj.collisionResponse && si.collisionResponse && sj.collisionResponse;
  13565. var mu = cm.friction;
  13566. // c.restitution = cm.restitution;
  13567. // If friction or restitution were specified in the material, use them
  13568. if(bi.material && bj.material){
  13569. if(bi.material.friction >= 0 && bj.material.friction >= 0){
  13570. mu = bi.material.friction * bj.material.friction;
  13571. }
  13572. if(bi.material.restitution >= 0 && bj.material.restitution >= 0){
  13573. c.restitution = bi.material.restitution * bj.material.restitution;
  13574. }
  13575. }
  13576. // c.setSpookParams(
  13577. // cm.contactEquationStiffness,
  13578. // cm.contactEquationRelaxation,
  13579. // dt
  13580. // );
  13581. solver.addEquation(c);
  13582. // // Add friction constraint equation
  13583. // if(mu > 0){
  13584. // // Create 2 tangent equations
  13585. // var mug = mu * gnorm;
  13586. // var reducedMass = (bi.invMass + bj.invMass);
  13587. // if(reducedMass > 0){
  13588. // reducedMass = 1/reducedMass;
  13589. // }
  13590. // var pool = frictionEquationPool;
  13591. // var c1 = pool.length ? pool.pop() : new FrictionEquation(bi,bj,mug*reducedMass);
  13592. // var c2 = pool.length ? pool.pop() : new FrictionEquation(bi,bj,mug*reducedMass);
  13593. // this.frictionEquations.push(c1, c2);
  13594. // c1.bi = c2.bi = bi;
  13595. // c1.bj = c2.bj = bj;
  13596. // c1.minForce = c2.minForce = -mug*reducedMass;
  13597. // c1.maxForce = c2.maxForce = mug*reducedMass;
  13598. // // Copy over the relative vectors
  13599. // c1.ri.copy(c.ri);
  13600. // c1.rj.copy(c.rj);
  13601. // c2.ri.copy(c.ri);
  13602. // c2.rj.copy(c.rj);
  13603. // // Construct tangents
  13604. // c.ni.tangents(c1.t, c2.t);
  13605. // // Set spook params
  13606. // c1.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, dt);
  13607. // c2.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, dt);
  13608. // c1.enabled = c2.enabled = c.enabled;
  13609. // // Add equations to solver
  13610. // solver.addEquation(c1);
  13611. // solver.addEquation(c2);
  13612. // }
  13613. if( bi.allowSleep &&
  13614. bi.type === Body.DYNAMIC &&
  13615. bi.sleepState === Body.SLEEPING &&
  13616. bj.sleepState === Body.AWAKE &&
  13617. bj.type !== Body.STATIC
  13618. ){
  13619. var speedSquaredB = bj.velocity.norm2() + bj.angularVelocity.norm2();
  13620. var speedLimitSquaredB = Math.pow(bj.sleepSpeedLimit,2);
  13621. if(speedSquaredB >= speedLimitSquaredB*2){
  13622. bi._wakeUpAfterNarrowphase = true;
  13623. }
  13624. }
  13625. if( bj.allowSleep &&
  13626. bj.type === Body.DYNAMIC &&
  13627. bj.sleepState === Body.SLEEPING &&
  13628. bi.sleepState === Body.AWAKE &&
  13629. bi.type !== Body.STATIC
  13630. ){
  13631. var speedSquaredA = bi.velocity.norm2() + bi.angularVelocity.norm2();
  13632. var speedLimitSquaredA = Math.pow(bi.sleepSpeedLimit,2);
  13633. if(speedSquaredA >= speedLimitSquaredA*2){
  13634. bj._wakeUpAfterNarrowphase = true;
  13635. }
  13636. }
  13637. // Now we know that i and j are in contact. Set collision matrix state
  13638. this.collisionMatrix.set(bi, bj, true);
  13639. if (!this.collisionMatrixPrevious.get(bi, bj)) {
  13640. // First contact!
  13641. // We reuse the collideEvent object, otherwise we will end up creating new objects for each new contact, even if there's no event listener attached.
  13642. World_step_collideEvent.body = bj;
  13643. World_step_collideEvent.contact = c;
  13644. bi.dispatchEvent(World_step_collideEvent);
  13645. World_step_collideEvent.body = bi;
  13646. bj.dispatchEvent(World_step_collideEvent);
  13647. }
  13648. this.bodyOverlapKeeper.set(bi.id, bj.id);
  13649. this.shapeOverlapKeeper.set(si.id, sj.id);
  13650. }
  13651. this.emitContactEvents();
  13652. if(doProfiling){
  13653. profile.makeContactConstraints = performance.now() - profilingStart;
  13654. profilingStart = performance.now();
  13655. }
  13656. // Wake up bodies
  13657. for(i=0; i!==N; i++){
  13658. var bi = bodies[i];
  13659. if(bi._wakeUpAfterNarrowphase){
  13660. bi.wakeUp();
  13661. bi._wakeUpAfterNarrowphase = false;
  13662. }
  13663. }
  13664. // Add user-added constraints
  13665. var Nconstraints = constraints.length;
  13666. for(i=0; i!==Nconstraints; i++){
  13667. var c = constraints[i];
  13668. c.update();
  13669. for(var j=0, Neq=c.equations.length; j!==Neq; j++){
  13670. var eq = c.equations[j];
  13671. solver.addEquation(eq);
  13672. }
  13673. }
  13674. // Solve the constrained system
  13675. solver.solve(dt,this);
  13676. if(doProfiling){
  13677. profile.solve = performance.now() - profilingStart;
  13678. }
  13679. // Remove all contacts from solver
  13680. solver.removeAllEquations();
  13681. // Apply damping, see http://code.google.com/p/bullet/issues/detail?id=74 for details
  13682. var pow = Math.pow;
  13683. for(i=0; i!==N; i++){
  13684. var bi = bodies[i];
  13685. if(bi.type & DYNAMIC){ // Only for dynamic bodies
  13686. var ld = pow(1.0 - bi.linearDamping,dt);
  13687. var v = bi.velocity;
  13688. v.mult(ld,v);
  13689. var av = bi.angularVelocity;
  13690. if(av){
  13691. var ad = pow(1.0 - bi.angularDamping,dt);
  13692. av.mult(ad,av);
  13693. }
  13694. }
  13695. }
  13696. this.dispatchEvent(World_step_preStepEvent);
  13697. // Invoke pre-step callbacks
  13698. for(i=0; i!==N; i++){
  13699. var bi = bodies[i];
  13700. if(bi.preStep){
  13701. bi.preStep.call(bi);
  13702. }
  13703. }
  13704. // Leap frog
  13705. // vnew = v + h*f/m
  13706. // xnew = x + h*vnew
  13707. if(doProfiling){
  13708. profilingStart = performance.now();
  13709. }
  13710. var stepnumber = this.stepnumber;
  13711. var quatNormalize = stepnumber % (this.quatNormalizeSkip + 1) === 0;
  13712. var quatNormalizeFast = this.quatNormalizeFast;
  13713. for(i=0; i!==N; i++){
  13714. bodies[i].integrate(dt, quatNormalize, quatNormalizeFast);
  13715. }
  13716. this.clearForces();
  13717. this.broadphase.dirty = true;
  13718. if(doProfiling){
  13719. profile.integrate = performance.now() - profilingStart;
  13720. }
  13721. // Update world time
  13722. this.time += dt;
  13723. this.stepnumber += 1;
  13724. this.dispatchEvent(World_step_postStepEvent);
  13725. // Invoke post-step callbacks
  13726. for(i=0; i!==N; i++){
  13727. var bi = bodies[i];
  13728. var postStep = bi.postStep;
  13729. if(postStep){
  13730. postStep.call(bi);
  13731. }
  13732. }
  13733. // Sleeping update
  13734. if(this.allowSleep){
  13735. for(i=0; i!==N; i++){
  13736. bodies[i].sleepTick(this.time);
  13737. }
  13738. }
  13739. };
  13740. World.prototype.emitContactEvents = (function(){
  13741. var additions = [];
  13742. var removals = [];
  13743. var beginContactEvent = {
  13744. type: 'beginContact',
  13745. bodyA: null,
  13746. bodyB: null
  13747. };
  13748. var endContactEvent = {
  13749. type: 'endContact',
  13750. bodyA: null,
  13751. bodyB: null
  13752. };
  13753. var beginShapeContactEvent = {
  13754. type: 'beginShapeContact',
  13755. bodyA: null,
  13756. bodyB: null,
  13757. shapeA: null,
  13758. shapeB: null
  13759. };
  13760. var endShapeContactEvent = {
  13761. type: 'endShapeContact',
  13762. bodyA: null,
  13763. bodyB: null,
  13764. shapeA: null,
  13765. shapeB: null
  13766. };
  13767. return function(){
  13768. var hasBeginContact = this.hasAnyEventListener('beginContact');
  13769. var hasEndContact = this.hasAnyEventListener('endContact');
  13770. if(hasBeginContact || hasEndContact){
  13771. this.bodyOverlapKeeper.getDiff(additions, removals);
  13772. }
  13773. if(hasBeginContact){
  13774. for (var i = 0, l = additions.length; i < l; i += 2) {
  13775. beginContactEvent.bodyA = this.getBodyById(additions[i]);
  13776. beginContactEvent.bodyB = this.getBodyById(additions[i+1]);
  13777. this.dispatchEvent(beginContactEvent);
  13778. }
  13779. beginContactEvent.bodyA = beginContactEvent.bodyB = null;
  13780. }
  13781. if(hasEndContact){
  13782. for (var i = 0, l = removals.length; i < l; i += 2) {
  13783. endContactEvent.bodyA = this.getBodyById(removals[i]);
  13784. endContactEvent.bodyB = this.getBodyById(removals[i+1]);
  13785. this.dispatchEvent(endContactEvent);
  13786. }
  13787. endContactEvent.bodyA = endContactEvent.bodyB = null;
  13788. }
  13789. additions.length = removals.length = 0;
  13790. var hasBeginShapeContact = this.hasAnyEventListener('beginShapeContact');
  13791. var hasEndShapeContact = this.hasAnyEventListener('endShapeContact');
  13792. if(hasBeginShapeContact || hasEndShapeContact){
  13793. this.shapeOverlapKeeper.getDiff(additions, removals);
  13794. }
  13795. if(hasBeginShapeContact){
  13796. for (var i = 0, l = additions.length; i < l; i += 2) {
  13797. var shapeA = this.getShapeById(additions[i]);
  13798. var shapeB = this.getShapeById(additions[i+1]);
  13799. beginShapeContactEvent.shapeA = shapeA;
  13800. beginShapeContactEvent.shapeB = shapeB;
  13801. beginShapeContactEvent.bodyA = shapeA.body;
  13802. beginShapeContactEvent.bodyB = shapeB.body;
  13803. this.dispatchEvent(beginShapeContactEvent);
  13804. }
  13805. beginShapeContactEvent.bodyA = beginShapeContactEvent.bodyB = beginShapeContactEvent.shapeA = beginShapeContactEvent.shapeB = null;
  13806. }
  13807. if(hasEndShapeContact){
  13808. for (var i = 0, l = removals.length; i < l; i += 2) {
  13809. var shapeA = this.getShapeById(removals[i]);
  13810. var shapeB = this.getShapeById(removals[i+1]);
  13811. endShapeContactEvent.shapeA = shapeA;
  13812. endShapeContactEvent.shapeB = shapeB;
  13813. endShapeContactEvent.bodyA = shapeA.body;
  13814. endShapeContactEvent.bodyB = shapeB.body;
  13815. this.dispatchEvent(endShapeContactEvent);
  13816. }
  13817. endShapeContactEvent.bodyA = endShapeContactEvent.bodyB = endShapeContactEvent.shapeA = endShapeContactEvent.shapeB = null;
  13818. }
  13819. };
  13820. })();
  13821. /**
  13822. * Sets all body forces in the world to zero.
  13823. * @method clearForces
  13824. */
  13825. World.prototype.clearForces = function(){
  13826. var bodies = this.bodies;
  13827. var N = bodies.length;
  13828. for(var i=0; i !== N; i++){
  13829. var b = bodies[i],
  13830. force = b.force,
  13831. tau = b.torque;
  13832. b.force.set(0,0,0);
  13833. b.torque.set(0,0,0);
  13834. }
  13835. };
  13836. },{"../collision/AABB":18,"../collision/ArrayCollisionMatrix":19,"../collision/NaiveBroadphase":22,"../collision/OverlapKeeper":24,"../collision/Ray":25,"../collision/RaycastResult":26,"../equations/ContactEquation":35,"../equations/FrictionEquation":37,"../material/ContactMaterial":40,"../material/Material":41,"../math/Quaternion":44,"../math/Vec3":46,"../objects/Body":47,"../shapes/Shape":59,"../solver/GSSolver":62,"../utils/EventTarget":65,"../utils/TupleDictionary":68,"./Narrowphase":71}],73:[function(require,module,exports){
  13837. var CANNON = require('cannon'),
  13838. quickhull = require('./lib/THREE.quickhull');
  13839. var PI_2 = Math.PI / 2;
  13840. var Type = {
  13841. BOX: 'Box',
  13842. CYLINDER: 'Cylinder',
  13843. SPHERE: 'Sphere',
  13844. HULL: 'ConvexPolyhedron',
  13845. MESH: 'Trimesh'
  13846. };
  13847. /**
  13848. * Given a THREE.Object3D instance, creates a corresponding CANNON shape.
  13849. * @param {THREE.Object3D} object
  13850. * @return {CANNON.Shape}
  13851. */
  13852. module.exports = CANNON.mesh2shape = function (object, options) {
  13853. options = options || {};
  13854. var geometry;
  13855. if (options.type === Type.BOX) {
  13856. return createBoundingBoxShape(object);
  13857. } else if (options.type === Type.CYLINDER) {
  13858. return createBoundingCylinderShape(object, options);
  13859. } else if (options.type === Type.SPHERE) {
  13860. return createBoundingSphereShape(object, options);
  13861. } else if (options.type === Type.HULL) {
  13862. return createConvexPolyhedron(object);
  13863. } else if (options.type === Type.MESH) {
  13864. geometry = getGeometry(object);
  13865. return geometry ? createTrimeshShape(geometry) : null;
  13866. } else if (options.type) {
  13867. throw new Error('[CANNON.mesh2shape] Invalid type "%s".', options.type);
  13868. }
  13869. geometry = getGeometry(object);
  13870. if (!geometry) return null;
  13871. var type = geometry.metadata
  13872. ? geometry.metadata.type
  13873. : geometry.type;
  13874. switch (type) {
  13875. case 'BoxGeometry':
  13876. case 'BoxBufferGeometry':
  13877. return createBoxShape(geometry);
  13878. case 'CylinderGeometry':
  13879. case 'CylinderBufferGeometry':
  13880. return createCylinderShape(geometry);
  13881. case 'PlaneGeometry':
  13882. case 'PlaneBufferGeometry':
  13883. return createPlaneShape(geometry);
  13884. case 'SphereGeometry':
  13885. case 'SphereBufferGeometry':
  13886. return createSphereShape(geometry);
  13887. case 'TubeGeometry':
  13888. case 'Geometry':
  13889. case 'BufferGeometry':
  13890. return createBoundingBoxShape(object);
  13891. default:
  13892. console.warn('Unrecognized geometry: "%s". Using bounding box as shape.', geometry.type);
  13893. return createBoxShape(geometry);
  13894. }
  13895. };
  13896. CANNON.mesh2shape.Type = Type;
  13897. /******************************************************************************
  13898. * Shape construction
  13899. */
  13900. /**
  13901. * @param {THREE.Geometry} geometry
  13902. * @return {CANNON.Shape}
  13903. */
  13904. function createBoxShape (geometry) {
  13905. var vertices = getVertices(geometry);
  13906. if (!vertices.length) return null;
  13907. geometry.computeBoundingBox();
  13908. var box = geometry.boundingBox;
  13909. return new CANNON.Box(new CANNON.Vec3(
  13910. (box.max.x - box.min.x) / 2,
  13911. (box.max.y - box.min.y) / 2,
  13912. (box.max.z - box.min.z) / 2
  13913. ));
  13914. }
  13915. /**
  13916. * Bounding box needs to be computed with the entire mesh, not just geometry.
  13917. * @param {THREE.Object3D} mesh
  13918. * @return {CANNON.Shape}
  13919. */
  13920. function createBoundingBoxShape (object) {
  13921. var shape, localPosition, worldPosition,
  13922. box = new THREE.Box3();
  13923. box.setFromObject(object);
  13924. if (!isFinite(box.min.lengthSq())) return null;
  13925. shape = new CANNON.Box(new CANNON.Vec3(
  13926. (box.max.x - box.min.x) / 2,
  13927. (box.max.y - box.min.y) / 2,
  13928. (box.max.z - box.min.z) / 2
  13929. ));
  13930. object.updateMatrixWorld();
  13931. worldPosition = new THREE.Vector3();
  13932. worldPosition.setFromMatrixPosition(object.matrixWorld);
  13933. localPosition = box.translate(worldPosition.negate()).getCenter();
  13934. if (localPosition.lengthSq()) {
  13935. shape.offset = localPosition;
  13936. }
  13937. return shape;
  13938. }
  13939. /**
  13940. * Computes 3D convex hull as a CANNON.ConvexPolyhedron.
  13941. * @param {THREE.Object3D} mesh
  13942. * @return {CANNON.Shape}
  13943. */
  13944. function createConvexPolyhedron (object) {
  13945. var i, vertices, faces, hull,
  13946. eps = 1e-4,
  13947. geometry = getGeometry(object);
  13948. if (!geometry || !geometry.vertices.length) return null;
  13949. // Perturb.
  13950. for (i = 0; i < geometry.vertices.length; i++) {
  13951. geometry.vertices[i].x += (Math.random() - 0.5) * eps;
  13952. geometry.vertices[i].y += (Math.random() - 0.5) * eps;
  13953. geometry.vertices[i].z += (Math.random() - 0.5) * eps;
  13954. }
  13955. // Compute the 3D convex hull.
  13956. hull = quickhull(geometry);
  13957. // Convert from THREE.Vector3 to CANNON.Vec3.
  13958. vertices = new Array(hull.vertices.length);
  13959. for (i = 0; i < hull.vertices.length; i++) {
  13960. vertices[i] = new CANNON.Vec3(hull.vertices[i].x, hull.vertices[i].y, hull.vertices[i].z);
  13961. }
  13962. // Convert from THREE.Face to Array<number>.
  13963. faces = new Array(hull.faces.length);
  13964. for (i = 0; i < hull.faces.length; i++) {
  13965. faces[i] = [hull.faces[i].a, hull.faces[i].b, hull.faces[i].c];
  13966. }
  13967. return new CANNON.ConvexPolyhedron(vertices, faces);
  13968. }
  13969. /**
  13970. * @param {THREE.Geometry} geometry
  13971. * @return {CANNON.Shape}
  13972. */
  13973. function createCylinderShape (geometry) {
  13974. var shape,
  13975. params = geometry.metadata
  13976. ? geometry.metadata.parameters
  13977. : geometry.parameters;
  13978. shape = new CANNON.Cylinder(
  13979. params.radiusTop,
  13980. params.radiusBottom,
  13981. params.height,
  13982. params.radialSegments
  13983. );
  13984. // Include metadata for serialization.
  13985. shape._type = CANNON.Shape.types.CYLINDER; // Patch schteppe/cannon.js#329.
  13986. shape.radiusTop = params.radiusTop;
  13987. shape.radiusBottom = params.radiusBottom;
  13988. shape.height = params.height;
  13989. shape.numSegments = params.radialSegments;
  13990. shape.orientation = new CANNON.Quaternion();
  13991. shape.orientation.setFromEuler(THREE.Math.degToRad(-90), 0, 0, 'XYZ').normalize();
  13992. return shape;
  13993. }
  13994. /**
  13995. * @param {THREE.Object3D} object
  13996. * @return {CANNON.Shape}
  13997. */
  13998. function createBoundingCylinderShape (object, options) {
  13999. var shape, height, radius,
  14000. box = new THREE.Box3(),
  14001. axes = ['x', 'y', 'z'],
  14002. majorAxis = options.cylinderAxis || 'y',
  14003. minorAxes = axes.splice(axes.indexOf(majorAxis), 1) && axes;
  14004. box.setFromObject(object);
  14005. if (!isFinite(box.min.lengthSq())) return null;
  14006. // Compute cylinder dimensions.
  14007. height = box.max[majorAxis] - box.min[majorAxis];
  14008. radius = 0.5 * Math.max(
  14009. box.max[minorAxes[0]] - box.min[minorAxes[0]],
  14010. box.max[minorAxes[1]] - box.min[minorAxes[1]]
  14011. );
  14012. // Create shape.
  14013. shape = new CANNON.Cylinder(radius, radius, height, 12);
  14014. // Include metadata for serialization.
  14015. shape._type = CANNON.Shape.types.CYLINDER; // Patch schteppe/cannon.js#329.
  14016. shape.radiusTop = radius;
  14017. shape.radiusBottom = radius;
  14018. shape.height = height;
  14019. shape.numSegments = 12;
  14020. shape.orientation = new CANNON.Quaternion();
  14021. shape.orientation.setFromEuler(
  14022. majorAxis === 'y' ? PI_2 : 0,
  14023. majorAxis === 'z' ? PI_2 : 0,
  14024. 0,
  14025. 'XYZ'
  14026. ).normalize();
  14027. return shape;
  14028. }
  14029. /**
  14030. * @param {THREE.Geometry} geometry
  14031. * @return {CANNON.Shape}
  14032. */
  14033. function createPlaneShape (geometry) {
  14034. geometry.computeBoundingBox();
  14035. var box = geometry.boundingBox;
  14036. return new CANNON.Box(new CANNON.Vec3(
  14037. (box.max.x - box.min.x) / 2 || 0.1,
  14038. (box.max.y - box.min.y) / 2 || 0.1,
  14039. (box.max.z - box.min.z) / 2 || 0.1
  14040. ));
  14041. }
  14042. /**
  14043. * @param {THREE.Geometry} geometry
  14044. * @return {CANNON.Shape}
  14045. */
  14046. function createSphereShape (geometry) {
  14047. var params = geometry.metadata
  14048. ? geometry.metadata.parameters
  14049. : geometry.parameters;
  14050. return new CANNON.Sphere(params.radius);
  14051. }
  14052. /**
  14053. * @param {THREE.Object3D} object
  14054. * @return {CANNON.Shape}
  14055. */
  14056. function createBoundingSphereShape (object, options) {
  14057. if (options.sphereRadius) {
  14058. return new CANNON.Sphere(options.sphereRadius);
  14059. }
  14060. var geometry = getGeometry(object);
  14061. if (!geometry) return null;
  14062. geometry.computeBoundingSphere();
  14063. return new CANNON.Sphere(geometry.boundingSphere.radius);
  14064. }
  14065. /**
  14066. * @param {THREE.Geometry} geometry
  14067. * @return {CANNON.Shape}
  14068. */
  14069. function createTrimeshShape (geometry) {
  14070. var indices,
  14071. vertices = getVertices(geometry);
  14072. if (!vertices.length) return null;
  14073. indices = Object.keys(vertices).map(Number);
  14074. return new CANNON.Trimesh(vertices, indices);
  14075. }
  14076. /******************************************************************************
  14077. * Utils
  14078. */
  14079. /**
  14080. * Returns a single geometry for the given object. If the object is compound,
  14081. * its geometries are automatically merged.
  14082. * @param {THREE.Object3D} object
  14083. * @return {THREE.Geometry}
  14084. */
  14085. function getGeometry (object) {
  14086. var matrix, mesh,
  14087. meshes = getMeshes(object),
  14088. tmp = new THREE.Geometry(),
  14089. combined = new THREE.Geometry();
  14090. if (meshes.length === 0) return null;
  14091. // Apply scale – it can't easily be applied to a CANNON.Shape later.
  14092. if (meshes.length === 1) {
  14093. var position = new THREE.Vector3(),
  14094. quaternion = new THREE.Quaternion(),
  14095. scale = new THREE.Vector3();
  14096. if (meshes[0].geometry.isBufferGeometry) {
  14097. if (meshes[0].geometry.attributes.position) {
  14098. tmp.fromBufferGeometry(meshes[0].geometry);
  14099. }
  14100. } else {
  14101. tmp = meshes[0].geometry.clone();
  14102. }
  14103. tmp.metadata = meshes[0].geometry.metadata;
  14104. meshes[0].updateMatrixWorld();
  14105. meshes[0].matrixWorld.decompose(position, quaternion, scale);
  14106. return tmp.scale(scale.x, scale.y, scale.z);
  14107. }
  14108. // Recursively merge geometry, preserving local transforms.
  14109. while ((mesh = meshes.pop())) {
  14110. mesh.updateMatrixWorld();
  14111. if (mesh.geometry.isBufferGeometry) {
  14112. tmp.fromBufferGeometry(mesh.geometry);
  14113. combined.merge(tmp, mesh.matrixWorld);
  14114. } else {
  14115. combined.merge(mesh.geometry, mesh.matrixWorld);
  14116. }
  14117. }
  14118. matrix = new THREE.Matrix4();
  14119. matrix.scale(object.scale);
  14120. combined.applyMatrix(matrix);
  14121. return combined;
  14122. }
  14123. /**
  14124. * @param {THREE.Geometry} geometry
  14125. * @return {Array<number>}
  14126. */
  14127. function getVertices (geometry) {
  14128. if (!geometry.attributes) {
  14129. geometry = new THREE.BufferGeometry().fromGeometry(geometry);
  14130. }
  14131. return (geometry.attributes.position || {}).array || [];
  14132. }
  14133. /**
  14134. * Returns a flat array of THREE.Mesh instances from the given object. If
  14135. * nested transformations are found, they are applied to child meshes
  14136. * as mesh.userData.matrix, so that each mesh has its position/rotation/scale
  14137. * independently of all of its parents except the top-level object.
  14138. * @param {THREE.Object3D} object
  14139. * @return {Array<THREE.Mesh>}
  14140. */
  14141. function getMeshes (object) {
  14142. var meshes = [];
  14143. object.traverse(function (o) {
  14144. if (o.type === 'Mesh') {
  14145. meshes.push(o);
  14146. }
  14147. });
  14148. return meshes;
  14149. }
  14150. },{"./lib/THREE.quickhull":74,"cannon":17}],74:[function(require,module,exports){
  14151. /**
  14152. QuickHull
  14153. ---------
  14154. The MIT License
  14155. Copyright &copy; 2010-2014 three.js authors
  14156. Permission is hereby granted, free of charge, to any person obtaining a copy
  14157. of this software and associated documentation files (the "Software"), to deal
  14158. in the Software without restriction, including without limitation the rights
  14159. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14160. copies of the Software, and to permit persons to whom the Software is
  14161. furnished to do so, subject to the following conditions:
  14162. The above copyright notice and this permission notice shall be included in
  14163. all copies or substantial portions of the Software.
  14164. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14165. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14166. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14167. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  14168. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  14169. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  14170. THE SOFTWARE.
  14171. @author mark lundin / http://mark-lundin.com
  14172. This is a 3D implementation of the Quick Hull algorithm.
  14173. It is a fast way of computing a convex hull with average complexity
  14174. of O(n log(n)).
  14175. It uses depends on three.js and is supposed to create THREE.Geometry.
  14176. It's also very messy
  14177. */
  14178. module.exports = (function(){
  14179. var faces = [],
  14180. faceStack = [],
  14181. i, NUM_POINTS, extremes,
  14182. max = 0,
  14183. dcur, current, j, v0, v1, v2, v3,
  14184. N, D;
  14185. var ab, ac, ax,
  14186. suba, subb, normal,
  14187. diff, subaA, subaB, subC;
  14188. function reset(){
  14189. ab = new THREE.Vector3(),
  14190. ac = new THREE.Vector3(),
  14191. ax = new THREE.Vector3(),
  14192. suba = new THREE.Vector3(),
  14193. subb = new THREE.Vector3(),
  14194. normal = new THREE.Vector3(),
  14195. diff = new THREE.Vector3(),
  14196. subaA = new THREE.Vector3(),
  14197. subaB = new THREE.Vector3(),
  14198. subC = new THREE.Vector3();
  14199. }
  14200. //temporary vectors
  14201. function process( points ){
  14202. // Iterate through all the faces and remove
  14203. while( faceStack.length > 0 ){
  14204. cull( faceStack.shift(), points );
  14205. }
  14206. }
  14207. var norm = function(){
  14208. var ca = new THREE.Vector3(),
  14209. ba = new THREE.Vector3(),
  14210. N = new THREE.Vector3();
  14211. return function( a, b, c ){
  14212. ca.subVectors( c, a );
  14213. ba.subVectors( b, a );
  14214. N.crossVectors( ca, ba );
  14215. return N.normalize();
  14216. }
  14217. }();
  14218. function getNormal( face, points ){
  14219. if( face.normal !== undefined ) return face.normal;
  14220. var p0 = points[face[0]],
  14221. p1 = points[face[1]],
  14222. p2 = points[face[2]];
  14223. ab.subVectors( p1, p0 );
  14224. ac.subVectors( p2, p0 );
  14225. normal.crossVectors( ac, ab );
  14226. normal.normalize();
  14227. return face.normal = normal.clone();
  14228. }
  14229. function assignPoints( face, pointset, points ){
  14230. // ASSIGNING POINTS TO FACE
  14231. var p0 = points[face[0]],
  14232. dots = [], apex,
  14233. norm = getNormal( face, points );
  14234. // Sory all the points by there distance from the plane
  14235. pointset.sort( function( aItem, bItem ){
  14236. dots[aItem.x/3] = dots[aItem.x/3] !== undefined ? dots[aItem.x/3] : norm.dot( suba.subVectors( aItem, p0 ));
  14237. dots[bItem.x/3] = dots[bItem.x/3] !== undefined ? dots[bItem.x/3] : norm.dot( subb.subVectors( bItem, p0 ));
  14238. return dots[aItem.x/3] - dots[bItem.x/3] ;
  14239. });
  14240. //TODO :: Must be a faster way of finding and index in this array
  14241. var index = pointset.length;
  14242. if( index === 1 ) dots[pointset[0].x/3] = norm.dot( suba.subVectors( pointset[0], p0 ));
  14243. while( index-- > 0 && dots[pointset[index].x/3] > 0 )
  14244. var point;
  14245. if( index + 1 < pointset.length && dots[pointset[index+1].x/3] > 0 ){
  14246. face.visiblePoints = pointset.splice( index + 1 );
  14247. }
  14248. }
  14249. function cull( face, points ){
  14250. var i = faces.length,
  14251. dot, visibleFace, currentFace,
  14252. visibleFaces = [face];
  14253. var apex = points.indexOf( face.visiblePoints.pop() );
  14254. // Iterate through all other faces...
  14255. while( i-- > 0 ){
  14256. currentFace = faces[i];
  14257. if( currentFace !== face ){
  14258. // ...and check if they're pointing in the same direction
  14259. dot = getNormal( currentFace, points ).dot( diff.subVectors( points[apex], points[currentFace[0]] ));
  14260. if( dot > 0 ){
  14261. visibleFaces.push( currentFace );
  14262. }
  14263. }
  14264. }
  14265. var index, neighbouringIndex, vertex;
  14266. // Determine Perimeter - Creates a bounded horizon
  14267. // 1. Pick an edge A out of all possible edges
  14268. // 2. Check if A is shared by any other face. a->b === b->a
  14269. // 2.1 for each edge in each triangle, isShared = ( f1.a == f2.a && f1.b == f2.b ) || ( f1.a == f2.b && f1.b == f2.a )
  14270. // 3. If not shared, then add to convex horizon set,
  14271. //pick an end point (N) of the current edge A and choose a new edge NA connected to A.
  14272. //Restart from 1.
  14273. // 4. If A is shared, it is not an horizon edge, therefore flag both faces that share this edge as candidates for culling
  14274. // 5. If candidate geometry is a degenrate triangle (ie. the tangent space normal cannot be computed) then remove that triangle from all further processing
  14275. var j = i = visibleFaces.length;
  14276. var isDistinct = false,
  14277. hasOneVisibleFace = i === 1,
  14278. cull = [],
  14279. perimeter = [],
  14280. edgeIndex = 0, compareFace, nextIndex,
  14281. a, b;
  14282. var allPoints = [];
  14283. var originFace = [visibleFaces[0][0], visibleFaces[0][1], visibleFaces[0][1], visibleFaces[0][2], visibleFaces[0][2], visibleFaces[0][0]];
  14284. if( visibleFaces.length === 1 ){
  14285. currentFace = visibleFaces[0];
  14286. perimeter = [currentFace[0], currentFace[1], currentFace[1], currentFace[2], currentFace[2], currentFace[0]];
  14287. // remove visible face from list of faces
  14288. if( faceStack.indexOf( currentFace ) > -1 ){
  14289. faceStack.splice( faceStack.indexOf( currentFace ), 1 );
  14290. }
  14291. if( currentFace.visiblePoints ) allPoints = allPoints.concat( currentFace.visiblePoints );
  14292. faces.splice( faces.indexOf( currentFace ), 1 );
  14293. }else{
  14294. while( i-- > 0 ){ // for each visible face
  14295. currentFace = visibleFaces[i];
  14296. // remove visible face from list of faces
  14297. if( faceStack.indexOf( currentFace ) > -1 ){
  14298. faceStack.splice( faceStack.indexOf( currentFace ), 1 );
  14299. }
  14300. if( currentFace.visiblePoints ) allPoints = allPoints.concat( currentFace.visiblePoints );
  14301. faces.splice( faces.indexOf( currentFace ), 1 );
  14302. var isSharedEdge;
  14303. cEdgeIndex = 0;
  14304. while( cEdgeIndex < 3 ){ // Iterate through it's edges
  14305. isSharedEdge = false;
  14306. j = visibleFaces.length;
  14307. a = currentFace[cEdgeIndex]
  14308. b = currentFace[(cEdgeIndex+1)%3];
  14309. while( j-- > 0 && !isSharedEdge ){ // find another visible faces
  14310. compareFace = visibleFaces[j];
  14311. edgeIndex = 0;
  14312. // isSharedEdge = compareFace == currentFace;
  14313. if( compareFace !== currentFace ){
  14314. while( edgeIndex < 3 && !isSharedEdge ){ //Check all it's indices
  14315. nextIndex = ( edgeIndex + 1 );
  14316. isSharedEdge = ( compareFace[edgeIndex] === a && compareFace[nextIndex%3] === b ) ||
  14317. ( compareFace[edgeIndex] === b && compareFace[nextIndex%3] === a );
  14318. edgeIndex++;
  14319. }
  14320. }
  14321. }
  14322. if( !isSharedEdge || hasOneVisibleFace ){
  14323. perimeter.push( a );
  14324. perimeter.push( b );
  14325. }
  14326. cEdgeIndex++;
  14327. }
  14328. }
  14329. }
  14330. // create new face for all pairs around edge
  14331. i = 0;
  14332. var l = perimeter.length/2;
  14333. var f;
  14334. while( i < l ){
  14335. f = [ perimeter[i*2+1], apex, perimeter[i*2] ];
  14336. assignPoints( f, allPoints, points );
  14337. faces.push( f )
  14338. if( f.visiblePoints !== undefined )faceStack.push( f );
  14339. i++;
  14340. }
  14341. }
  14342. var distSqPointSegment = function(){
  14343. var ab = new THREE.Vector3(),
  14344. ac = new THREE.Vector3(),
  14345. bc = new THREE.Vector3();
  14346. return function( a, b, c ){
  14347. ab.subVectors( b, a );
  14348. ac.subVectors( c, a );
  14349. bc.subVectors( c, b );
  14350. var e = ac.dot(ab);
  14351. if (e < 0.0) return ac.dot( ac );
  14352. var f = ab.dot( ab );
  14353. if (e >= f) return bc.dot( bc );
  14354. return ac.dot( ac ) - e * e / f;
  14355. }
  14356. }();
  14357. return function( geometry ){
  14358. reset();
  14359. points = geometry.vertices;
  14360. faces = [],
  14361. faceStack = [],
  14362. i = NUM_POINTS = points.length,
  14363. extremes = points.slice( 0, 6 ),
  14364. max = 0;
  14365. /*
  14366. * FIND EXTREMETIES
  14367. */
  14368. while( i-- > 0 ){
  14369. if( points[i].x < extremes[0].x ) extremes[0] = points[i];
  14370. if( points[i].x > extremes[1].x ) extremes[1] = points[i];
  14371. if( points[i].y < extremes[2].y ) extremes[2] = points[i];
  14372. if( points[i].y < extremes[3].y ) extremes[3] = points[i];
  14373. if( points[i].z < extremes[4].z ) extremes[4] = points[i];
  14374. if( points[i].z < extremes[5].z ) extremes[5] = points[i];
  14375. }
  14376. /*
  14377. * Find the longest line between the extremeties
  14378. */
  14379. j = i = 6;
  14380. while( i-- > 0 ){
  14381. j = i - 1;
  14382. while( j-- > 0 ){
  14383. if( max < (dcur = extremes[i].distanceToSquared( extremes[j] )) ){
  14384. max = dcur;
  14385. v0 = extremes[ i ];
  14386. v1 = extremes[ j ];
  14387. }
  14388. }
  14389. }
  14390. // 3. Find the most distant point to the line segment, this creates a plane
  14391. i = 6;
  14392. max = 0;
  14393. while( i-- > 0 ){
  14394. dcur = distSqPointSegment( v0, v1, extremes[i]);
  14395. if( max < dcur ){
  14396. max = dcur;
  14397. v2 = extremes[ i ];
  14398. }
  14399. }
  14400. // 4. Find the most distant point to the plane.
  14401. N = norm(v0, v1, v2);
  14402. D = N.dot( v0 );
  14403. max = 0;
  14404. i = NUM_POINTS;
  14405. while( i-- > 0 ){
  14406. dcur = Math.abs( points[i].dot( N ) - D );
  14407. if( max < dcur ){
  14408. max = dcur;
  14409. v3 = points[i];
  14410. }
  14411. }
  14412. var v0Index = points.indexOf( v0 ),
  14413. v1Index = points.indexOf( v1 ),
  14414. v2Index = points.indexOf( v2 ),
  14415. v3Index = points.indexOf( v3 );
  14416. // We now have a tetrahedron as the base geometry.
  14417. // Now we must subdivide the
  14418. var tetrahedron =[
  14419. [ v2Index, v1Index, v0Index ],
  14420. [ v1Index, v3Index, v0Index ],
  14421. [ v2Index, v3Index, v1Index ],
  14422. [ v0Index, v3Index, v2Index ],
  14423. ];
  14424. subaA.subVectors( v1, v0 ).normalize();
  14425. subaB.subVectors( v2, v0 ).normalize();
  14426. subC.subVectors ( v3, v0 ).normalize();
  14427. var sign = subC.dot( new THREE.Vector3().crossVectors( subaB, subaA ));
  14428. // Reverse the winding if negative sign
  14429. if( sign < 0 ){
  14430. tetrahedron[0].reverse();
  14431. tetrahedron[1].reverse();
  14432. tetrahedron[2].reverse();
  14433. tetrahedron[3].reverse();
  14434. }
  14435. //One for each face of the pyramid
  14436. var pointsCloned = points.slice();
  14437. pointsCloned.splice( pointsCloned.indexOf( v0 ), 1 );
  14438. pointsCloned.splice( pointsCloned.indexOf( v1 ), 1 );
  14439. pointsCloned.splice( pointsCloned.indexOf( v2 ), 1 );
  14440. pointsCloned.splice( pointsCloned.indexOf( v3 ), 1 );
  14441. var i = tetrahedron.length;
  14442. while( i-- > 0 ){
  14443. assignPoints( tetrahedron[i], pointsCloned, points );
  14444. if( tetrahedron[i].visiblePoints !== undefined ){
  14445. faceStack.push( tetrahedron[i] );
  14446. }
  14447. faces.push( tetrahedron[i] );
  14448. }
  14449. process( points );
  14450. // Assign to our geometry object
  14451. var ll = faces.length;
  14452. while( ll-- > 0 ){
  14453. geometry.faces[ll] = new THREE.Face3( faces[ll][2], faces[ll][1], faces[ll][0], faces[ll].normal )
  14454. }
  14455. geometry.normalsNeedUpdate = true;
  14456. return geometry;
  14457. }
  14458. }())
  14459. },{}],75:[function(require,module,exports){
  14460. var EPS = 0.1;
  14461. module.exports = {
  14462. schema: {
  14463. enabled: {default: true},
  14464. mode: {default: 'teleport', oneOf: ['teleport', 'animate']},
  14465. animateSpeed: {default: 3.0}
  14466. },
  14467. init: function () {
  14468. this.active = true;
  14469. this.checkpoint = null;
  14470. this.offset = new THREE.Vector3();
  14471. this.position = new THREE.Vector3();
  14472. this.targetPosition = new THREE.Vector3();
  14473. },
  14474. play: function () { this.active = true; },
  14475. pause: function () { this.active = false; },
  14476. setCheckpoint: function (checkpoint) {
  14477. var el = this.el;
  14478. if (!this.active) return;
  14479. if (this.checkpoint === checkpoint) return;
  14480. if (this.checkpoint) {
  14481. el.emit('navigation-end', {checkpoint: this.checkpoint});
  14482. }
  14483. this.checkpoint = checkpoint;
  14484. this.sync();
  14485. // Ignore new checkpoint if we're already there.
  14486. if (this.position.distanceTo(this.targetPosition) < EPS) {
  14487. this.checkpoint = null;
  14488. return;
  14489. }
  14490. el.emit('navigation-start', {checkpoint: checkpoint});
  14491. if (this.data.mode === 'teleport') {
  14492. this.el.setAttribute('position', this.targetPosition);
  14493. this.checkpoint = null;
  14494. el.emit('navigation-end', {checkpoint: checkpoint});
  14495. }
  14496. },
  14497. isVelocityActive: function () {
  14498. return !!(this.active && this.checkpoint);
  14499. },
  14500. getVelocity: function () {
  14501. if (!this.active) return;
  14502. var data = this.data,
  14503. offset = this.offset,
  14504. position = this.position,
  14505. targetPosition = this.targetPosition,
  14506. checkpoint = this.checkpoint;
  14507. this.sync();
  14508. if (position.distanceTo(targetPosition) < EPS) {
  14509. this.checkpoint = null;
  14510. this.el.emit('navigation-end', {checkpoint: checkpoint});
  14511. return offset.set(0, 0, 0);
  14512. }
  14513. offset.setLength(data.animateSpeed);
  14514. return offset;
  14515. },
  14516. sync: function () {
  14517. var offset = this.offset,
  14518. position = this.position,
  14519. targetPosition = this.targetPosition;
  14520. position.copy(this.el.getAttribute('position'));
  14521. targetPosition.copy(this.checkpoint.object3D.getWorldPosition());
  14522. targetPosition.add(this.checkpoint.components.checkpoint.getOffset());
  14523. offset.copy(targetPosition).sub(position);
  14524. }
  14525. };
  14526. },{}],76:[function(require,module,exports){
  14527. /**
  14528. * Gamepad controls for A-Frame.
  14529. *
  14530. * Stripped-down version of: https://github.com/donmccurdy/aframe-gamepad-controls
  14531. *
  14532. * For more information about the Gamepad API, see:
  14533. * https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API/Using_the_Gamepad_API
  14534. */
  14535. var GamepadButton = require('../../lib/GamepadButton'),
  14536. GamepadButtonEvent = require('../../lib/GamepadButtonEvent');
  14537. var JOYSTICK_EPS = 0.2;
  14538. module.exports = {
  14539. /*******************************************************************
  14540. * Statics
  14541. */
  14542. GamepadButton: GamepadButton,
  14543. /*******************************************************************
  14544. * Schema
  14545. */
  14546. schema: {
  14547. // Controller 0-3
  14548. controller: { default: 0, oneOf: [0, 1, 2, 3] },
  14549. // Enable/disable features
  14550. enabled: { default: true },
  14551. // Debugging
  14552. debug: { default: false }
  14553. },
  14554. /*******************************************************************
  14555. * Core
  14556. */
  14557. /**
  14558. * Called once when component is attached. Generally for initial setup.
  14559. */
  14560. init: function () {
  14561. var scene = this.el.sceneEl;
  14562. this.prevTime = window.performance.now();
  14563. // Button state
  14564. this.buttons = {};
  14565. scene.addBehavior(this);
  14566. },
  14567. /**
  14568. * Called when component is attached and when component data changes.
  14569. * Generally modifies the entity based on the data.
  14570. */
  14571. update: function () { this.tick(); },
  14572. /**
  14573. * Called on each iteration of main render loop.
  14574. */
  14575. tick: function () {
  14576. this.updateButtonState();
  14577. },
  14578. /**
  14579. * Called when a component is removed (e.g., via removeAttribute).
  14580. * Generally undoes all modifications to the entity.
  14581. */
  14582. remove: function () { },
  14583. /*******************************************************************
  14584. * Universal controls - movement
  14585. */
  14586. isVelocityActive: function () {
  14587. if (!this.data.enabled || !this.isConnected()) return false;
  14588. var dpad = this.getDpad(),
  14589. joystick0 = this.getJoystick(0),
  14590. inputX = dpad.x || joystick0.x,
  14591. inputY = dpad.y || joystick0.y;
  14592. return Math.abs(inputX) > JOYSTICK_EPS || Math.abs(inputY) > JOYSTICK_EPS;
  14593. },
  14594. getVelocityDelta: function () {
  14595. var dpad = this.getDpad(),
  14596. joystick0 = this.getJoystick(0),
  14597. inputX = dpad.x || joystick0.x,
  14598. inputY = dpad.y || joystick0.y,
  14599. dVelocity = new THREE.Vector3();
  14600. if (Math.abs(inputX) > JOYSTICK_EPS) {
  14601. dVelocity.x += inputX;
  14602. }
  14603. if (Math.abs(inputY) > JOYSTICK_EPS) {
  14604. dVelocity.z += inputY;
  14605. }
  14606. return dVelocity;
  14607. },
  14608. /*******************************************************************
  14609. * Universal controls - rotation
  14610. */
  14611. isRotationActive: function () {
  14612. if (!this.data.enabled || !this.isConnected()) return false;
  14613. var joystick1 = this.getJoystick(1);
  14614. return Math.abs(joystick1.x) > JOYSTICK_EPS || Math.abs(joystick1.y) > JOYSTICK_EPS;
  14615. },
  14616. getRotationDelta: function () {
  14617. var lookVector = this.getJoystick(1);
  14618. if (Math.abs(lookVector.x) <= JOYSTICK_EPS) lookVector.x = 0;
  14619. if (Math.abs(lookVector.y) <= JOYSTICK_EPS) lookVector.y = 0;
  14620. return lookVector;
  14621. },
  14622. /*******************************************************************
  14623. * Button events
  14624. */
  14625. updateButtonState: function () {
  14626. var gamepad = this.getGamepad();
  14627. if (this.data.enabled && gamepad) {
  14628. // Fire DOM events for button state changes.
  14629. for (var i = 0; i < gamepad.buttons.length; i++) {
  14630. if (gamepad.buttons[i].pressed && !this.buttons[i]) {
  14631. this.emit(new GamepadButtonEvent('gamepadbuttondown', i, gamepad.buttons[i]));
  14632. } else if (!gamepad.buttons[i].pressed && this.buttons[i]) {
  14633. this.emit(new GamepadButtonEvent('gamepadbuttonup', i, gamepad.buttons[i]));
  14634. }
  14635. this.buttons[i] = gamepad.buttons[i].pressed;
  14636. }
  14637. } else if (Object.keys(this.buttons)) {
  14638. // Reset state if controls are disabled or controller is lost.
  14639. this.buttons = {};
  14640. }
  14641. },
  14642. emit: function (event) {
  14643. // Emit original event.
  14644. this.el.emit(event.type, event);
  14645. // Emit convenience event, identifying button index.
  14646. this.el.emit(
  14647. event.type + ':' + event.index,
  14648. new GamepadButtonEvent(event.type, event.index, event)
  14649. );
  14650. },
  14651. /*******************************************************************
  14652. * Gamepad state
  14653. */
  14654. /**
  14655. * Returns the Gamepad instance attached to the component. If connected,
  14656. * a proxy-controls component may provide access to Gamepad input from a
  14657. * remote device.
  14658. *
  14659. * @return {Gamepad}
  14660. */
  14661. getGamepad: function () {
  14662. var localGamepad = navigator.getGamepads
  14663. && navigator.getGamepads()[this.data.controller],
  14664. proxyControls = this.el.sceneEl.components['proxy-controls'],
  14665. proxyGamepad = proxyControls && proxyControls.isConnected()
  14666. && proxyControls.getGamepad(this.data.controller);
  14667. return proxyGamepad || localGamepad;
  14668. },
  14669. /**
  14670. * Returns the state of the given button.
  14671. * @param {number} index The button (0-N) for which to find state.
  14672. * @return {GamepadButton}
  14673. */
  14674. getButton: function (index) {
  14675. return this.getGamepad().buttons[index];
  14676. },
  14677. /**
  14678. * Returns state of the given axis. Axes are labelled 0-N, where 0-1 will
  14679. * represent X/Y on the first joystick, and 2-3 X/Y on the second.
  14680. * @param {number} index The axis (0-N) for which to find state.
  14681. * @return {number} On the interval [-1,1].
  14682. */
  14683. getAxis: function (index) {
  14684. return this.getGamepad().axes[index];
  14685. },
  14686. /**
  14687. * Returns the state of the given joystick (0 or 1) as a THREE.Vector2.
  14688. * @param {number} id The joystick (0, 1) for which to find state.
  14689. * @return {THREE.Vector2}
  14690. */
  14691. getJoystick: function (index) {
  14692. var gamepad = this.getGamepad();
  14693. switch (index) {
  14694. case 0: return new THREE.Vector2(gamepad.axes[0], gamepad.axes[1]);
  14695. case 1: return new THREE.Vector2(gamepad.axes[2], gamepad.axes[3]);
  14696. default: throw new Error('Unexpected joystick index "%d".', index);
  14697. }
  14698. },
  14699. /**
  14700. * Returns the state of the dpad as a THREE.Vector2.
  14701. * @return {THREE.Vector2}
  14702. */
  14703. getDpad: function () {
  14704. var gamepad = this.getGamepad();
  14705. if (!gamepad.buttons[GamepadButton.DPAD_RIGHT]) {
  14706. return new THREE.Vector2();
  14707. }
  14708. return new THREE.Vector2(
  14709. (gamepad.buttons[GamepadButton.DPAD_RIGHT].pressed ? 1 : 0)
  14710. + (gamepad.buttons[GamepadButton.DPAD_LEFT].pressed ? -1 : 0),
  14711. (gamepad.buttons[GamepadButton.DPAD_UP].pressed ? -1 : 0)
  14712. + (gamepad.buttons[GamepadButton.DPAD_DOWN].pressed ? 1 : 0)
  14713. );
  14714. },
  14715. /**
  14716. * Returns true if the gamepad is currently connected to the system.
  14717. * @return {boolean}
  14718. */
  14719. isConnected: function () {
  14720. var gamepad = this.getGamepad();
  14721. return !!(gamepad && gamepad.connected);
  14722. },
  14723. /**
  14724. * Returns a string containing some information about the controller. Result
  14725. * may vary across browsers, for a given controller.
  14726. * @return {string}
  14727. */
  14728. getID: function () {
  14729. return this.getGamepad().id;
  14730. }
  14731. };
  14732. },{"../../lib/GamepadButton":2,"../../lib/GamepadButtonEvent":3}],77:[function(require,module,exports){
  14733. var radToDeg = THREE.Math.radToDeg,
  14734. isMobile = AFRAME.utils.device.isMobile();
  14735. module.exports = {
  14736. schema: {
  14737. enabled: {default: true},
  14738. standing: {default: true}
  14739. },
  14740. init: function () {
  14741. this.isPositionCalibrated = false;
  14742. this.dolly = new THREE.Object3D();
  14743. this.hmdEuler = new THREE.Euler();
  14744. this.previousHMDPosition = new THREE.Vector3();
  14745. this.deltaHMDPosition = new THREE.Vector3();
  14746. this.vrControls = new THREE.VRControls(this.dolly);
  14747. this.rotation = new THREE.Vector3();
  14748. },
  14749. update: function () {
  14750. var data = this.data;
  14751. var vrControls = this.vrControls;
  14752. vrControls.standing = data.standing;
  14753. vrControls.update();
  14754. },
  14755. tick: function () {
  14756. this.vrControls.update();
  14757. },
  14758. remove: function () {
  14759. this.vrControls.dispose();
  14760. },
  14761. isRotationActive: function () {
  14762. var hmdEuler = this.hmdEuler;
  14763. if (!this.data.enabled || !(this.el.sceneEl.is('vr-mode') || isMobile)) {
  14764. return false;
  14765. }
  14766. hmdEuler.setFromQuaternion(this.dolly.quaternion, 'YXZ');
  14767. return !isNullVector(hmdEuler);
  14768. },
  14769. getRotation: function () {
  14770. var hmdEuler = this.hmdEuler;
  14771. return this.rotation.set(
  14772. radToDeg(hmdEuler.x),
  14773. radToDeg(hmdEuler.y),
  14774. radToDeg(hmdEuler.z)
  14775. );
  14776. },
  14777. isVelocityActive: function () {
  14778. var deltaHMDPosition = this.deltaHMDPosition;
  14779. var previousHMDPosition = this.previousHMDPosition;
  14780. var currentHMDPosition = this.calculateHMDPosition();
  14781. this.isPositionCalibrated = this.isPositionCalibrated || !isNullVector(previousHMDPosition);
  14782. if (!this.data.enabled || !this.el.sceneEl.is('vr-mode') || isMobile) {
  14783. return false;
  14784. }
  14785. deltaHMDPosition.copy(currentHMDPosition).sub(previousHMDPosition);
  14786. previousHMDPosition.copy(currentHMDPosition);
  14787. return this.isPositionCalibrated && !isNullVector(deltaHMDPosition);
  14788. },
  14789. getPositionDelta: function () {
  14790. return this.deltaHMDPosition;
  14791. },
  14792. calculateHMDPosition: function () {
  14793. var dolly = this.dolly;
  14794. var position = new THREE.Vector3();
  14795. dolly.updateMatrix();
  14796. position.setFromMatrixPosition(dolly.matrix);
  14797. return position;
  14798. }
  14799. };
  14800. function isNullVector (vector) {
  14801. return vector.x === 0 && vector.y === 0 && vector.z === 0;
  14802. }
  14803. },{}],78:[function(require,module,exports){
  14804. var physics = require('aframe-physics-system');
  14805. module.exports = {
  14806. 'checkpoint-controls': require('./checkpoint-controls'),
  14807. 'gamepad-controls': require('./gamepad-controls'),
  14808. 'hmd-controls': require('./hmd-controls'),
  14809. 'keyboard-controls': require('./keyboard-controls'),
  14810. 'mouse-controls': require('./mouse-controls'),
  14811. 'touch-controls': require('./touch-controls'),
  14812. 'universal-controls': require('./universal-controls'),
  14813. registerAll: function (AFRAME) {
  14814. if (this._registered) return;
  14815. AFRAME = AFRAME || window.AFRAME;
  14816. physics.registerAll();
  14817. if (!AFRAME.components['checkpoint-controls']) AFRAME.registerComponent('checkpoint-controls', this['checkpoint-controls']);
  14818. if (!AFRAME.components['gamepad-controls']) AFRAME.registerComponent('gamepad-controls', this['gamepad-controls']);
  14819. if (!AFRAME.components['hmd-controls']) AFRAME.registerComponent('hmd-controls', this['hmd-controls']);
  14820. if (!AFRAME.components['keyboard-controls']) AFRAME.registerComponent('keyboard-controls', this['keyboard-controls']);
  14821. if (!AFRAME.components['mouse-controls']) AFRAME.registerComponent('mouse-controls', this['mouse-controls']);
  14822. if (!AFRAME.components['touch-controls']) AFRAME.registerComponent('touch-controls', this['touch-controls']);
  14823. if (!AFRAME.components['universal-controls']) AFRAME.registerComponent('universal-controls', this['universal-controls']);
  14824. this._registered = true;
  14825. }
  14826. };
  14827. },{"./checkpoint-controls":75,"./gamepad-controls":76,"./hmd-controls":77,"./keyboard-controls":79,"./mouse-controls":80,"./touch-controls":81,"./universal-controls":82,"aframe-physics-system":5}],79:[function(require,module,exports){
  14828. require('../../lib/keyboard.polyfill');
  14829. var MAX_DELTA = 0.2,
  14830. PROXY_FLAG = '__keyboard-controls-proxy';
  14831. var KeyboardEvent = window.KeyboardEvent;
  14832. /**
  14833. * Keyboard Controls component.
  14834. *
  14835. * Stripped-down version of: https://github.com/donmccurdy/aframe-keyboard-controls
  14836. *
  14837. * Bind keyboard events to components, or control your entities with the WASD keys.
  14838. *
  14839. * Why use KeyboardEvent.code? "This is set to a string representing the key that was pressed to
  14840. * generate the KeyboardEvent, without taking the current keyboard layout (e.g., QWERTY vs.
  14841. * Dvorak), locale (e.g., English vs. French), or any modifier keys into account. This is useful
  14842. * when you care about which physical key was pressed, rather thanwhich character it corresponds
  14843. * to. For example, if you’re a writing a game, you might want a certain set of keys to move the
  14844. * player in different directions, and that mapping should ideally be independent of keyboard
  14845. * layout. See: https://developers.google.com/web/updates/2016/04/keyboardevent-keys-codes
  14846. *
  14847. * @namespace wasd-controls
  14848. * keys the entity moves and if you release it will stop. Easing simulates friction.
  14849. * to the entity when pressing the keys.
  14850. * @param {bool} [enabled=true] - To completely enable or disable the controls
  14851. */
  14852. module.exports = {
  14853. schema: {
  14854. enabled: { default: true },
  14855. debug: { default: false }
  14856. },
  14857. init: function () {
  14858. this.dVelocity = new THREE.Vector3();
  14859. this.localKeys = {};
  14860. this.listeners = {
  14861. keydown: this.onKeyDown.bind(this),
  14862. keyup: this.onKeyUp.bind(this),
  14863. blur: this.onBlur.bind(this)
  14864. };
  14865. this.attachEventListeners();
  14866. },
  14867. /*******************************************************************
  14868. * Movement
  14869. */
  14870. isVelocityActive: function () {
  14871. return this.data.enabled && !!Object.keys(this.getKeys()).length;
  14872. },
  14873. getVelocityDelta: function () {
  14874. var data = this.data,
  14875. keys = this.getKeys();
  14876. this.dVelocity.set(0, 0, 0);
  14877. if (data.enabled) {
  14878. if (keys.KeyW || keys.ArrowUp) { this.dVelocity.z -= 1; }
  14879. if (keys.KeyA || keys.ArrowLeft) { this.dVelocity.x -= 1; }
  14880. if (keys.KeyS || keys.ArrowDown) { this.dVelocity.z += 1; }
  14881. if (keys.KeyD || keys.ArrowRight) { this.dVelocity.x += 1; }
  14882. }
  14883. return this.dVelocity.clone();
  14884. },
  14885. /*******************************************************************
  14886. * Events
  14887. */
  14888. play: function () {
  14889. this.attachEventListeners();
  14890. },
  14891. pause: function () {
  14892. this.removeEventListeners();
  14893. },
  14894. remove: function () {
  14895. this.pause();
  14896. },
  14897. attachEventListeners: function () {
  14898. window.addEventListener('keydown', this.listeners.keydown, false);
  14899. window.addEventListener('keyup', this.listeners.keyup, false);
  14900. window.addEventListener('blur', this.listeners.blur, false);
  14901. },
  14902. removeEventListeners: function () {
  14903. window.removeEventListener('keydown', this.listeners.keydown);
  14904. window.removeEventListener('keyup', this.listeners.keyup);
  14905. window.removeEventListener('blur', this.listeners.blur);
  14906. },
  14907. onKeyDown: function (event) {
  14908. if (AFRAME.utils.shouldCaptureKeyEvent(event)) {
  14909. this.localKeys[event.code] = true;
  14910. this.emit(event);
  14911. }
  14912. },
  14913. onKeyUp: function (event) {
  14914. if (AFRAME.utils.shouldCaptureKeyEvent(event)) {
  14915. delete this.localKeys[event.code];
  14916. this.emit(event);
  14917. }
  14918. },
  14919. onBlur: function () {
  14920. for (var code in this.localKeys) {
  14921. if (this.localKeys.hasOwnProperty(code)) {
  14922. delete this.localKeys[code];
  14923. }
  14924. }
  14925. },
  14926. emit: function (event) {
  14927. // TODO - keydown only initially?
  14928. // TODO - where the f is the spacebar
  14929. // Emit original event.
  14930. if (PROXY_FLAG in event) {
  14931. // TODO - Method never triggered.
  14932. this.el.emit(event.type, event);
  14933. }
  14934. // Emit convenience event, identifying key.
  14935. this.el.emit(event.type + ':' + event.code, new KeyboardEvent(event.type, event));
  14936. if (this.data.debug) console.log(event.type + ':' + event.code);
  14937. },
  14938. /*******************************************************************
  14939. * Accessors
  14940. */
  14941. isPressed: function (code) {
  14942. return code in this.getKeys();
  14943. },
  14944. getKeys: function () {
  14945. if (this.isProxied()) {
  14946. return this.el.sceneEl.components['proxy-controls'].getKeyboard();
  14947. }
  14948. return this.localKeys;
  14949. },
  14950. isProxied: function () {
  14951. var proxyControls = this.el.sceneEl.components['proxy-controls'];
  14952. return proxyControls && proxyControls.isConnected();
  14953. }
  14954. };
  14955. },{"../../lib/keyboard.polyfill":4}],80:[function(require,module,exports){
  14956. document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock;
  14957. /**
  14958. * Mouse + Pointerlock controls.
  14959. *
  14960. * Based on: https://github.com/aframevr/aframe/pull/1056
  14961. */
  14962. module.exports = {
  14963. schema: {
  14964. enabled: { default: true },
  14965. pointerlockEnabled: { default: true },
  14966. sensitivity: { default: 1 / 25 }
  14967. },
  14968. init: function () {
  14969. this.mouseDown = false;
  14970. this.pointerLocked = false;
  14971. this.lookVector = new THREE.Vector2();
  14972. this.bindMethods();
  14973. },
  14974. update: function (previousData) {
  14975. var data = this.data;
  14976. if (previousData.pointerlockEnabled && !data.pointerlockEnabled && this.pointerLocked) {
  14977. document.exitPointerLock();
  14978. }
  14979. },
  14980. play: function () {
  14981. this.addEventListeners();
  14982. },
  14983. pause: function () {
  14984. this.removeEventListeners();
  14985. this.lookVector.set(0, 0);
  14986. },
  14987. remove: function () {
  14988. this.pause();
  14989. },
  14990. bindMethods: function () {
  14991. this.onMouseDown = this.onMouseDown.bind(this);
  14992. this.onMouseMove = this.onMouseMove.bind(this);
  14993. this.onMouseUp = this.onMouseUp.bind(this);
  14994. this.onMouseUp = this.onMouseUp.bind(this);
  14995. this.onPointerLockChange = this.onPointerLockChange.bind(this);
  14996. this.onPointerLockChange = this.onPointerLockChange.bind(this);
  14997. this.onPointerLockChange = this.onPointerLockChange.bind(this);
  14998. },
  14999. addEventListeners: function () {
  15000. var sceneEl = this.el.sceneEl;
  15001. var canvasEl = sceneEl.canvas;
  15002. var data = this.data;
  15003. if (!canvasEl) {
  15004. sceneEl.addEventListener('render-target-loaded', this.addEventListeners.bind(this));
  15005. return;
  15006. }
  15007. canvasEl.addEventListener('mousedown', this.onMouseDown, false);
  15008. canvasEl.addEventListener('mousemove', this.onMouseMove, false);
  15009. canvasEl.addEventListener('mouseup', this.onMouseUp, false);
  15010. canvasEl.addEventListener('mouseout', this.onMouseUp, false);
  15011. if (data.pointerlockEnabled) {
  15012. document.addEventListener('pointerlockchange', this.onPointerLockChange, false);
  15013. document.addEventListener('mozpointerlockchange', this.onPointerLockChange, false);
  15014. document.addEventListener('pointerlockerror', this.onPointerLockError, false);
  15015. }
  15016. },
  15017. removeEventListeners: function () {
  15018. var canvasEl = this.el.sceneEl && this.el.sceneEl.canvas;
  15019. if (canvasEl) {
  15020. canvasEl.removeEventListener('mousedown', this.onMouseDown, false);
  15021. canvasEl.removeEventListener('mousemove', this.onMouseMove, false);
  15022. canvasEl.removeEventListener('mouseup', this.onMouseUp, false);
  15023. canvasEl.removeEventListener('mouseout', this.onMouseUp, false);
  15024. }
  15025. document.removeEventListener('pointerlockchange', this.onPointerLockChange, false);
  15026. document.removeEventListener('mozpointerlockchange', this.onPointerLockChange, false);
  15027. document.removeEventListener('pointerlockerror', this.onPointerLockError, false);
  15028. },
  15029. isRotationActive: function () {
  15030. return this.data.enabled && (this.mouseDown || this.pointerLocked);
  15031. },
  15032. /**
  15033. * Returns the sum of all mouse movement since last call.
  15034. */
  15035. getRotationDelta: function () {
  15036. var dRotation = this.lookVector.clone().multiplyScalar(this.data.sensitivity);
  15037. this.lookVector.set(0, 0);
  15038. return dRotation;
  15039. },
  15040. onMouseMove: function (event) {
  15041. var previousMouseEvent = this.previousMouseEvent;
  15042. if (!this.data.enabled || !(this.mouseDown || this.pointerLocked)) {
  15043. return;
  15044. }
  15045. var movementX = event.movementX || event.mozMovementX || 0;
  15046. var movementY = event.movementY || event.mozMovementY || 0;
  15047. if (!this.pointerLocked) {
  15048. movementX = event.screenX - previousMouseEvent.screenX;
  15049. movementY = event.screenY - previousMouseEvent.screenY;
  15050. }
  15051. this.lookVector.x += movementX;
  15052. this.lookVector.y += movementY;
  15053. this.previousMouseEvent = event;
  15054. },
  15055. onMouseDown: function (event) {
  15056. var canvasEl = this.el.sceneEl.canvas,
  15057. isEditing = (AFRAME.INSPECTOR || {}).opened;
  15058. this.mouseDown = true;
  15059. this.previousMouseEvent = event;
  15060. if (this.data.pointerlockEnabled && !this.pointerLocked && !isEditing) {
  15061. if (canvasEl.requestPointerLock) {
  15062. canvasEl.requestPointerLock();
  15063. } else if (canvasEl.mozRequestPointerLock) {
  15064. canvasEl.mozRequestPointerLock();
  15065. }
  15066. }
  15067. },
  15068. onMouseUp: function () {
  15069. this.mouseDown = false;
  15070. },
  15071. onPointerLockChange: function () {
  15072. this.pointerLocked = !!(document.pointerLockElement || document.mozPointerLockElement);
  15073. },
  15074. onPointerLockError: function () {
  15075. this.pointerLocked = false;
  15076. }
  15077. };
  15078. },{}],81:[function(require,module,exports){
  15079. module.exports = {
  15080. schema: {
  15081. enabled: { default: true }
  15082. },
  15083. init: function () {
  15084. this.dVelocity = new THREE.Vector3();
  15085. this.bindMethods();
  15086. },
  15087. play: function () {
  15088. this.addEventListeners();
  15089. },
  15090. pause: function () {
  15091. this.removeEventListeners();
  15092. this.dVelocity.set(0, 0, 0);
  15093. },
  15094. remove: function () {
  15095. this.pause();
  15096. },
  15097. addEventListeners: function () {
  15098. var sceneEl = this.el.sceneEl;
  15099. var canvasEl = sceneEl.canvas;
  15100. if (!canvasEl) {
  15101. sceneEl.addEventListener('render-target-loaded', this.addEventListeners.bind(this));
  15102. return;
  15103. }
  15104. canvasEl.addEventListener('touchstart', this.onTouchStart);
  15105. canvasEl.addEventListener('touchend', this.onTouchEnd);
  15106. },
  15107. removeEventListeners: function () {
  15108. var canvasEl = this.el.sceneEl && this.el.sceneEl.canvas;
  15109. if (!canvasEl) { return; }
  15110. canvasEl.removeEventListener('touchstart', this.onTouchStart);
  15111. canvasEl.removeEventListener('touchend', this.onTouchEnd);
  15112. },
  15113. isVelocityActive: function () {
  15114. return this.data.enabled && this.isMoving;
  15115. },
  15116. getVelocityDelta: function () {
  15117. this.dVelocity.z = this.isMoving ? -1 : 0;
  15118. return this.dVelocity.clone();
  15119. },
  15120. bindMethods: function () {
  15121. this.onTouchStart = this.onTouchStart.bind(this);
  15122. this.onTouchEnd = this.onTouchEnd.bind(this);
  15123. },
  15124. onTouchStart: function (e) {
  15125. this.isMoving = true;
  15126. e.preventDefault();
  15127. },
  15128. onTouchEnd: function (e) {
  15129. this.isMoving = false;
  15130. e.preventDefault();
  15131. }
  15132. };
  15133. },{}],82:[function(require,module,exports){
  15134. /**
  15135. * Universal Controls
  15136. *
  15137. * @author Don McCurdy <dm@donmccurdy.com>
  15138. */
  15139. var COMPONENT_SUFFIX = '-controls',
  15140. MAX_DELTA = 0.2, // ms
  15141. PI_2 = Math.PI / 2;
  15142. module.exports = {
  15143. /*******************************************************************
  15144. * Schema
  15145. */
  15146. dependencies: ['velocity', 'rotation'],
  15147. schema: {
  15148. enabled: { default: true },
  15149. movementEnabled: { default: true },
  15150. movementControls: { default: ['gamepad', 'keyboard', 'touch', 'hmd'] },
  15151. rotationEnabled: { default: true },
  15152. rotationControls: { default: ['hmd', 'gamepad', 'mouse'] },
  15153. movementSpeed: { default: 5 }, // m/s
  15154. movementEasing: { default: 15 }, // m/s2
  15155. movementEasingY: { default: 0 }, // m/s2
  15156. movementAcceleration: { default: 80 }, // m/s2
  15157. rotationSensitivity: { default: 0.05 }, // radians/frame, ish
  15158. fly: { default: false },
  15159. },
  15160. /*******************************************************************
  15161. * Lifecycle
  15162. */
  15163. init: function () {
  15164. var rotation = this.el.getAttribute('rotation');
  15165. if (this.el.hasAttribute('look-controls') && this.data.rotationEnabled) {
  15166. console.error('[universal-controls] The `universal-controls` component is a replacement '
  15167. + 'for `look-controls`, and cannot be used in combination with it.');
  15168. }
  15169. // Movement
  15170. this.velocity = new THREE.Vector3();
  15171. // Rotation
  15172. this.pitch = new THREE.Object3D();
  15173. this.pitch.rotation.x = THREE.Math.degToRad(rotation.x);
  15174. this.yaw = new THREE.Object3D();
  15175. this.yaw.position.y = 10;
  15176. this.yaw.rotation.y = THREE.Math.degToRad(rotation.y);
  15177. this.yaw.add(this.pitch);
  15178. this.heading = new THREE.Euler(0, 0, 0, 'YXZ');
  15179. if (this.el.sceneEl.hasLoaded) {
  15180. this.injectControls();
  15181. } else {
  15182. this.el.sceneEl.addEventListener('loaded', this.injectControls.bind(this));
  15183. }
  15184. },
  15185. update: function () {
  15186. if (this.el.sceneEl.hasLoaded) {
  15187. this.injectControls();
  15188. }
  15189. },
  15190. injectControls: function () {
  15191. var i, name,
  15192. data = this.data;
  15193. for (i = 0; i < data.movementControls.length; i++) {
  15194. name = data.movementControls[i] + COMPONENT_SUFFIX;
  15195. if (!this.el.components[name]) {
  15196. this.el.setAttribute(name, '');
  15197. }
  15198. }
  15199. for (i = 0; i < data.rotationControls.length; i++) {
  15200. name = data.rotationControls[i] + COMPONENT_SUFFIX;
  15201. if (!this.el.components[name]) {
  15202. this.el.setAttribute(name, '');
  15203. }
  15204. }
  15205. },
  15206. /*******************************************************************
  15207. * Tick
  15208. */
  15209. tick: function (t, dt) {
  15210. if (!dt) { return; }
  15211. // Update rotation.
  15212. if (this.data.rotationEnabled) this.updateRotation(dt);
  15213. // Update velocity. If FPS is too low, reset.
  15214. if (this.data.movementEnabled && dt / 1000 > MAX_DELTA) {
  15215. this.velocity.set(0, 0, 0);
  15216. this.el.setAttribute('velocity', this.velocity);
  15217. } else {
  15218. this.updateVelocity(dt);
  15219. }
  15220. },
  15221. /*******************************************************************
  15222. * Rotation
  15223. */
  15224. updateRotation: function (dt) {
  15225. var control, dRotation,
  15226. data = this.data;
  15227. for (var i = 0, l = data.rotationControls.length; i < l; i++) {
  15228. control = this.el.components[data.rotationControls[i] + COMPONENT_SUFFIX];
  15229. if (control && control.isRotationActive()) {
  15230. if (control.getRotationDelta) {
  15231. dRotation = control.getRotationDelta(dt);
  15232. dRotation.multiplyScalar(data.rotationSensitivity);
  15233. this.yaw.rotation.y -= dRotation.x;
  15234. this.pitch.rotation.x -= dRotation.y;
  15235. this.pitch.rotation.x = Math.max(-PI_2, Math.min(PI_2, this.pitch.rotation.x));
  15236. this.el.setAttribute('rotation', {
  15237. x: THREE.Math.radToDeg(this.pitch.rotation.x),
  15238. y: THREE.Math.radToDeg(this.yaw.rotation.y),
  15239. z: 0
  15240. });
  15241. } else if (control.getRotation) {
  15242. this.el.setAttribute('rotation', control.getRotation());
  15243. } else {
  15244. throw new Error('Incompatible rotation controls: %s', data.rotationControls[i]);
  15245. }
  15246. break;
  15247. }
  15248. }
  15249. },
  15250. /*******************************************************************
  15251. * Movement
  15252. */
  15253. updateVelocity: function (dt) {
  15254. var control, dVelocity,
  15255. velocity = this.velocity,
  15256. data = this.data;
  15257. if (data.movementEnabled) {
  15258. for (var i = 0, l = data.movementControls.length; i < l; i++) {
  15259. control = this.el.components[data.movementControls[i] + COMPONENT_SUFFIX];
  15260. if (control && control.isVelocityActive()) {
  15261. if (control.getVelocityDelta) {
  15262. dVelocity = control.getVelocityDelta(dt);
  15263. } else if (control.getVelocity) {
  15264. this.el.setAttribute('velocity', control.getVelocity());
  15265. return;
  15266. } else if (control.getPositionDelta) {
  15267. velocity.copy(control.getPositionDelta(dt).multiplyScalar(1000 / dt));
  15268. this.el.setAttribute('velocity', velocity);
  15269. return;
  15270. } else {
  15271. throw new Error('Incompatible movement controls: ', data.movementControls[i]);
  15272. }
  15273. break;
  15274. }
  15275. }
  15276. }
  15277. velocity.copy(this.el.getAttribute('velocity'));
  15278. velocity.x -= velocity.x * data.movementEasing * dt / 1000;
  15279. velocity.y -= velocity.y * data.movementEasingY * dt / 1000;
  15280. velocity.z -= velocity.z * data.movementEasing * dt / 1000;
  15281. if (dVelocity && data.movementEnabled) {
  15282. // Set acceleration
  15283. if (dVelocity.length() > 1) {
  15284. dVelocity.setLength(this.data.movementAcceleration * dt / 1000);
  15285. } else {
  15286. dVelocity.multiplyScalar(this.data.movementAcceleration * dt / 1000);
  15287. }
  15288. // Rotate to heading
  15289. var rotation = this.el.getAttribute('rotation');
  15290. if (rotation) {
  15291. this.heading.set(
  15292. data.fly ? THREE.Math.degToRad(rotation.x) : 0,
  15293. THREE.Math.degToRad(rotation.y),
  15294. 0
  15295. );
  15296. dVelocity.applyEuler(this.heading);
  15297. }
  15298. velocity.add(dVelocity);
  15299. // TODO - Several issues here:
  15300. // (1) Interferes w/ gravity.
  15301. // (2) Interferes w/ jumping.
  15302. // (3) Likely to interfere w/ relative position to moving platform.
  15303. // if (velocity.length() > data.movementSpeed) {
  15304. // velocity.setLength(data.movementSpeed);
  15305. // }
  15306. }
  15307. this.el.setAttribute('velocity', velocity);
  15308. }
  15309. };
  15310. },{}]},{},[1]);