aframe-extras.misc.js 476 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851
  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/misc').registerAll();
  3. },{"./src/misc":75}],2:[function(require,module,exports){
  4. var CANNON = require('cannon'),
  5. math = require('./src/components/math');
  6. module.exports = {
  7. 'dynamic-body': require('./src/components/body/dynamic-body'),
  8. 'static-body': require('./src/components/body/static-body'),
  9. 'constraint': require('./src/components/constraint'),
  10. 'system': require('./src/system/physics'),
  11. registerAll: function (AFRAME) {
  12. if (this._registered) return;
  13. AFRAME = AFRAME || window.AFRAME;
  14. math.registerAll();
  15. if (!AFRAME.systems.physics) AFRAME.registerSystem('physics', this.system);
  16. if (!AFRAME.components['dynamic-body']) AFRAME.registerComponent('dynamic-body', this['dynamic-body']);
  17. if (!AFRAME.components['static-body']) AFRAME.registerComponent('static-body', this['static-body']);
  18. if (!AFRAME.components['constraint']) AFRAME.registerComponent('constraint', this['constraint']);
  19. this._registered = true;
  20. }
  21. };
  22. // Export CANNON.js.
  23. window.CANNON = window.CANNON || CANNON;
  24. },{"./src/components/body/dynamic-body":5,"./src/components/body/static-body":6,"./src/components/constraint":7,"./src/components/math":8,"./src/system/physics":12,"cannon":14}],3:[function(require,module,exports){
  25. /**
  26. * CANNON.shape2mesh
  27. *
  28. * Source: http://schteppe.github.io/cannon.js/build/cannon.demo.js
  29. * Author: @schteppe
  30. */
  31. var CANNON = require('cannon');
  32. CANNON.shape2mesh = function(body){
  33. var obj = new THREE.Object3D();
  34. for (var l = 0; l < body.shapes.length; l++) {
  35. var shape = body.shapes[l];
  36. var mesh;
  37. switch(shape.type){
  38. case CANNON.Shape.types.SPHERE:
  39. var sphere_geometry = new THREE.SphereGeometry( shape.radius, 8, 8);
  40. mesh = new THREE.Mesh( sphere_geometry, this.currentMaterial );
  41. break;
  42. case CANNON.Shape.types.PARTICLE:
  43. mesh = new THREE.Mesh( this.particleGeo, this.particleMaterial );
  44. var s = this.settings;
  45. mesh.scale.set(s.particleSize,s.particleSize,s.particleSize);
  46. break;
  47. case CANNON.Shape.types.PLANE:
  48. var geometry = new THREE.PlaneGeometry(10, 10, 4, 4);
  49. mesh = new THREE.Object3D();
  50. var submesh = new THREE.Object3D();
  51. var ground = new THREE.Mesh( geometry, this.currentMaterial );
  52. ground.scale.set(100, 100, 100);
  53. submesh.add(ground);
  54. ground.castShadow = true;
  55. ground.receiveShadow = true;
  56. mesh.add(submesh);
  57. break;
  58. case CANNON.Shape.types.BOX:
  59. var box_geometry = new THREE.BoxGeometry( shape.halfExtents.x*2,
  60. shape.halfExtents.y*2,
  61. shape.halfExtents.z*2 );
  62. mesh = new THREE.Mesh( box_geometry, this.currentMaterial );
  63. break;
  64. case CANNON.Shape.types.CONVEXPOLYHEDRON:
  65. var geo = new THREE.Geometry();
  66. // Add vertices
  67. for (var i = 0; i < shape.vertices.length; i++) {
  68. var v = shape.vertices[i];
  69. geo.vertices.push(new THREE.Vector3(v.x, v.y, v.z));
  70. }
  71. for(var i=0; i < shape.faces.length; i++){
  72. var face = shape.faces[i];
  73. // add triangles
  74. var a = face[0];
  75. for (var j = 1; j < face.length - 1; j++) {
  76. var b = face[j];
  77. var c = face[j + 1];
  78. geo.faces.push(new THREE.Face3(a, b, c));
  79. }
  80. }
  81. geo.computeBoundingSphere();
  82. geo.computeFaceNormals();
  83. mesh = new THREE.Mesh( geo, this.currentMaterial );
  84. break;
  85. case CANNON.Shape.types.HEIGHTFIELD:
  86. var geometry = new THREE.Geometry();
  87. var v0 = new CANNON.Vec3();
  88. var v1 = new CANNON.Vec3();
  89. var v2 = new CANNON.Vec3();
  90. for (var xi = 0; xi < shape.data.length - 1; xi++) {
  91. for (var yi = 0; yi < shape.data[xi].length - 1; yi++) {
  92. for (var k = 0; k < 2; k++) {
  93. shape.getConvexTrianglePillar(xi, yi, k===0);
  94. v0.copy(shape.pillarConvex.vertices[0]);
  95. v1.copy(shape.pillarConvex.vertices[1]);
  96. v2.copy(shape.pillarConvex.vertices[2]);
  97. v0.vadd(shape.pillarOffset, v0);
  98. v1.vadd(shape.pillarOffset, v1);
  99. v2.vadd(shape.pillarOffset, v2);
  100. geometry.vertices.push(
  101. new THREE.Vector3(v0.x, v0.y, v0.z),
  102. new THREE.Vector3(v1.x, v1.y, v1.z),
  103. new THREE.Vector3(v2.x, v2.y, v2.z)
  104. );
  105. var i = geometry.vertices.length - 3;
  106. geometry.faces.push(new THREE.Face3(i, i+1, i+2));
  107. }
  108. }
  109. }
  110. geometry.computeBoundingSphere();
  111. geometry.computeFaceNormals();
  112. mesh = new THREE.Mesh(geometry, this.currentMaterial);
  113. break;
  114. case CANNON.Shape.types.TRIMESH:
  115. var geometry = new THREE.Geometry();
  116. var v0 = new CANNON.Vec3();
  117. var v1 = new CANNON.Vec3();
  118. var v2 = new CANNON.Vec3();
  119. for (var i = 0; i < shape.indices.length / 3; i++) {
  120. shape.getTriangleVertices(i, v0, v1, v2);
  121. geometry.vertices.push(
  122. new THREE.Vector3(v0.x, v0.y, v0.z),
  123. new THREE.Vector3(v1.x, v1.y, v1.z),
  124. new THREE.Vector3(v2.x, v2.y, v2.z)
  125. );
  126. var j = geometry.vertices.length - 3;
  127. geometry.faces.push(new THREE.Face3(j, j+1, j+2));
  128. }
  129. geometry.computeBoundingSphere();
  130. geometry.computeFaceNormals();
  131. mesh = new THREE.Mesh(geometry, this.currentMaterial);
  132. break;
  133. default:
  134. throw "Visual type not recognized: "+shape.type;
  135. }
  136. mesh.receiveShadow = true;
  137. mesh.castShadow = true;
  138. if(mesh.children){
  139. for(var i=0; i<mesh.children.length; i++){
  140. mesh.children[i].castShadow = true;
  141. mesh.children[i].receiveShadow = true;
  142. if(mesh.children[i]){
  143. for(var j=0; j<mesh.children[i].length; j++){
  144. mesh.children[i].children[j].castShadow = true;
  145. mesh.children[i].children[j].receiveShadow = true;
  146. }
  147. }
  148. }
  149. }
  150. var o = body.shapeOffsets[l];
  151. var q = body.shapeOrientations[l];
  152. mesh.position.set(o.x, o.y, o.z);
  153. mesh.quaternion.set(q.x, q.y, q.z, q.w);
  154. obj.add(mesh);
  155. }
  156. return obj;
  157. };
  158. module.exports = CANNON.shape2mesh;
  159. },{"cannon":14}],4:[function(require,module,exports){
  160. var CANNON = require('cannon'),
  161. mesh2shape = require('three-to-cannon');
  162. require('../../../lib/CANNON-shape2mesh');
  163. module.exports = {
  164. schema: {
  165. shape: {default: 'auto', oneOf: ['auto', 'box', 'cylinder', 'sphere', 'hull', 'none']},
  166. cylinderAxis: {default: 'y', oneOf: ['x', 'y', 'z']},
  167. sphereRadius: {default: NaN}
  168. },
  169. /**
  170. * Initializes a body component, assigning it to the physics system and binding listeners for
  171. * parsing the elements geometry.
  172. */
  173. init: function () {
  174. this.system = this.el.sceneEl.systems.physics;
  175. if (this.el.sceneEl.hasLoaded) {
  176. this.initBody();
  177. } else {
  178. this.el.sceneEl.addEventListener('loaded', this.initBody.bind(this));
  179. }
  180. },
  181. /**
  182. * Parses an element's geometry and component metadata to create a CANNON.Body instance for the
  183. * component.
  184. */
  185. initBody: function () {
  186. var shape,
  187. el = this.el,
  188. data = this.data,
  189. pos = el.getAttribute('position');
  190. this.body = new CANNON.Body({
  191. mass: data.mass || 0,
  192. material: this.system.material,
  193. position: new CANNON.Vec3(pos.x, pos.y, pos.z),
  194. linearDamping: data.linearDamping,
  195. angularDamping: data.angularDamping
  196. });
  197. // Matrix World must be updated at root level, if scale is to be applied – updateMatrixWorld()
  198. // only checks an object's parent, not the rest of the ancestors. Hence, a wrapping entity with
  199. // scale="0.5 0.5 0.5" will be ignored.
  200. // Reference: https://github.com/mrdoob/three.js/blob/master/src/core/Object3D.js#L511-L541
  201. // Potential fix: https://github.com/mrdoob/three.js/pull/7019
  202. this.el.object3D.updateMatrixWorld(true);
  203. if(data.shape !== 'none') {
  204. var options = data.shape === 'auto' ? undefined : AFRAME.utils.extend({}, this.data, {
  205. type: mesh2shape.Type[data.shape.toUpperCase()]
  206. });
  207. shape = mesh2shape(this.el.object3D, options);
  208. if (!shape) {
  209. this.el.addEventListener('model-loaded', this.initBody.bind(this));
  210. return;
  211. }
  212. this.body.addShape(shape, shape.offset, shape.orientation);
  213. // Show wireframe
  214. if (this.system.debug) {
  215. this.createWireframe(this.body, shape);
  216. }
  217. }
  218. // Apply rotation
  219. var rot = el.getAttribute('rotation');
  220. this.body.quaternion.setFromEuler(
  221. THREE.Math.degToRad(rot.x),
  222. THREE.Math.degToRad(rot.y),
  223. THREE.Math.degToRad(rot.z),
  224. 'XYZ'
  225. ).normalize();
  226. this.el.body = this.body;
  227. this.body.el = this.el;
  228. this.isLoaded = true;
  229. // If component wasn't initialized when play() was called, finish up.
  230. if (this.isPlaying) {
  231. this._play();
  232. }
  233. this.el.emit('body-loaded', {body: this.el.body});
  234. },
  235. /**
  236. * Registers the component with the physics system, if ready.
  237. */
  238. play: function () {
  239. if (this.isLoaded) this._play();
  240. },
  241. /**
  242. * Internal helper to register component with physics system.
  243. */
  244. _play: function () {
  245. this.system.addBehavior(this, this.system.Phase.SIMULATE);
  246. this.system.addBody(this.body);
  247. if (this.wireframe) this.el.sceneEl.object3D.add(this.wireframe);
  248. this.syncToPhysics();
  249. },
  250. /**
  251. * Unregisters the component with the physics system.
  252. */
  253. pause: function () {
  254. if (!this.isLoaded) return;
  255. this.system.removeBehavior(this, this.system.Phase.SIMULATE);
  256. this.system.removeBody(this.body);
  257. if (this.wireframe) this.el.sceneEl.object3D.remove(this.wireframe);
  258. },
  259. /**
  260. * Removes the component and all physics and scene side effects.
  261. */
  262. remove: function () {
  263. this.pause();
  264. delete this.body.el;
  265. delete this.body;
  266. delete this.el.body;
  267. delete this.wireframe;
  268. },
  269. /**
  270. * Creates a wireframe for the body, for debugging.
  271. * TODO(donmccurdy) – Refactor this into a standalone utility or component.
  272. * @param {CANNON.Body} body
  273. * @param {CANNON.Shape} shape
  274. */
  275. createWireframe: function (body, shape) {
  276. var offset = shape.offset,
  277. orientation = shape.orientation,
  278. mesh = CANNON.shape2mesh(body).children[0];
  279. this.wireframe = new THREE.LineSegments(
  280. new THREE.EdgesGeometry(mesh.geometry),
  281. new THREE.LineBasicMaterial({color: 0xff0000})
  282. );
  283. if (offset) {
  284. this.wireframe.offset = offset.clone();
  285. }
  286. if (orientation) {
  287. orientation.inverse(orientation);
  288. this.wireframe.orientation = new THREE.Quaternion(
  289. orientation.x,
  290. orientation.y,
  291. orientation.z,
  292. orientation.w
  293. );
  294. }
  295. this.syncWireframe();
  296. },
  297. /**
  298. * Updates the debugging wireframe's position and rotation.
  299. */
  300. syncWireframe: function () {
  301. var offset,
  302. wireframe = this.wireframe;
  303. if (!this.wireframe) return;
  304. // Apply rotation. If the shape required custom orientation, also apply
  305. // that on the wireframe.
  306. wireframe.quaternion.copy(this.body.quaternion);
  307. if (wireframe.orientation) {
  308. wireframe.quaternion.multiply(wireframe.orientation);
  309. }
  310. // Apply position. If the shape required custom offset, also apply that on
  311. // the wireframe.
  312. wireframe.position.copy(this.body.position);
  313. if (wireframe.offset) {
  314. offset = wireframe.offset.clone().applyQuaternion(wireframe.quaternion);
  315. wireframe.position.add(offset);
  316. }
  317. wireframe.updateMatrix();
  318. },
  319. /**
  320. * Updates the CANNON.Body instance's position, velocity, and rotation, based on the scene.
  321. */
  322. syncToPhysics: (function () {
  323. var q = new THREE.Quaternion(),
  324. v = new THREE.Vector3();
  325. return function () {
  326. var el = this.el,
  327. parentEl = el.parentEl,
  328. body = this.body;
  329. if (!body) return;
  330. if (el.components.velocity) body.velocity.copy(el.getAttribute('velocity'));
  331. if (parentEl.isScene) {
  332. body.quaternion.copy(el.object3D.quaternion);
  333. body.position.copy(el.object3D.position);
  334. } else {
  335. el.object3D.getWorldQuaternion(q);
  336. body.quaternion.copy(q);
  337. el.object3D.getWorldPosition(v);
  338. body.position.copy(v);
  339. }
  340. if (this.wireframe) this.syncWireframe();
  341. };
  342. }()),
  343. /**
  344. * Updates the scene object's position and rotation, based on the physics simulation.
  345. */
  346. syncFromPhysics: (function () {
  347. var v = new THREE.Vector3(),
  348. q1 = new THREE.Quaternion(),
  349. q2 = new THREE.Quaternion();
  350. return function () {
  351. var el = this.el,
  352. parentEl = el.parentEl,
  353. body = this.body;
  354. if (!body) return;
  355. if (parentEl.isScene) {
  356. el.setAttribute('quaternion', body.quaternion);
  357. el.setAttribute('position', body.position);
  358. } else {
  359. // TODO - Nested rotation doesn't seem to be working as expected.
  360. q1.copy(body.quaternion);
  361. parentEl.object3D.getWorldQuaternion(q2);
  362. q1.multiply(q2.inverse());
  363. el.setAttribute('quaternion', {x: q1.x, y: q1.y, z: q1.z, w: q1.w});
  364. v.copy(body.position);
  365. parentEl.object3D.worldToLocal(v);
  366. el.setAttribute('position', {x: v.x, y: v.y, z: v.z});
  367. }
  368. if (this.wireframe) this.syncWireframe();
  369. };
  370. }())
  371. };
  372. },{"../../../lib/CANNON-shape2mesh":3,"cannon":14,"three-to-cannon":70}],5:[function(require,module,exports){
  373. var Body = require('./body');
  374. /**
  375. * Dynamic body.
  376. *
  377. * Moves according to physics simulation, and may collide with other objects.
  378. */
  379. module.exports = AFRAME.utils.extend({}, Body, {
  380. dependencies: ['quaternion', 'velocity'],
  381. schema: AFRAME.utils.extend({}, Body.schema, {
  382. mass: { default: 5 },
  383. linearDamping: { default: 0.01 },
  384. angularDamping: { default: 0.01 }
  385. }),
  386. step: function () {
  387. this.syncFromPhysics();
  388. }
  389. });
  390. },{"./body":4}],6:[function(require,module,exports){
  391. var Body = require('./body');
  392. /**
  393. * Static body.
  394. *
  395. * Solid body with a fixed position. Unaffected by gravity and collisions, but
  396. * other objects may collide with it.
  397. */
  398. module.exports = AFRAME.utils.extend({}, Body, {
  399. step: function () {
  400. this.syncToPhysics();
  401. }
  402. });
  403. },{"./body":4}],7:[function(require,module,exports){
  404. var CANNON = require('cannon');
  405. module.exports = {
  406. dependencies: ['dynamic-body'],
  407. multiple: true,
  408. schema: {
  409. // Type of constraint.
  410. type: {default: 'lock', oneOf: ['coneTwist', 'distance', 'hinge', 'lock', 'pointToPoint']},
  411. // Target (other) body for the constraint.
  412. target: {type: 'selector'},
  413. // Maximum force that should be applied to constraint the bodies.
  414. maxForce: {default: 1e6, min: 0},
  415. // If true, bodies can collide when they are connected.
  416. collideConnected: {default: true},
  417. // Wake up bodies when connected.
  418. wakeUpBodies: {default: true},
  419. // The distance to be kept between the bodies. If 0, will be set to current distance.
  420. distance: {default: 0, min: 0},
  421. // Offset of the hinge or point-to-point constraint, defined locally in the body.
  422. pivot: {type: 'vec3'},
  423. targetPivot: {type: 'vec3'},
  424. // An axis that each body can rotate around, defined locally to that body.
  425. axis: {type: 'vec3', default: { x: 0, y: 0, z: 1 }},
  426. targetAxis: {type: 'vec3', default: { x: 0, y: 0, z: 1}}
  427. },
  428. init: function () {
  429. this.system = this.el.sceneEl.systems.physics;
  430. this.constraint = /* {CANNON.Constraint} */ null;
  431. },
  432. remove: function () {
  433. if (!this.constraint) return;
  434. this.system.world.removeConstraint(this.constraint);
  435. this.constraint = null;
  436. },
  437. update: function () {
  438. var el = this.el,
  439. data = this.data;
  440. this.remove();
  441. if (!el.body || !data.target.body) {
  442. (el.body ? data.target : el).addEventListener('body-loaded', this.update.bind(this, {}));
  443. return;
  444. }
  445. this.constraint = this.createConstraint();
  446. this.system.world.addConstraint(this.constraint);
  447. },
  448. /**
  449. * Creates a new constraint, given current component data. The CANNON.js constructors are a bit
  450. * different for each constraint type.
  451. * @return {CANNON.Constraint}
  452. */
  453. createConstraint: function () {
  454. var data = this.data,
  455. pivot = new CANNON.Vec3(data.pivot.x, data.pivot.y, data.pivot.z),
  456. targetPivot = new CANNON.Vec3(data.targetPivot.x, data.targetPivot.y, data.targetPivot.z),
  457. axis = new CANNON.Vec3(data.axis.x, data.axis.y, data.axis.z),
  458. targetAxis= new CANNON.Vec3(data.targetAxis.x, data.targetAxis.y, data.targetAxis.z);
  459. var constraint;
  460. switch (data.type) {
  461. case 'lock':
  462. constraint = new CANNON.LockConstraint(
  463. this.el.body,
  464. data.target.body,
  465. {maxForce: data.maxForce}
  466. );
  467. break;
  468. case 'distance':
  469. constraint = new CANNON.DistanceConstraint(
  470. this.el.body,
  471. data.target.body,
  472. data.distance,
  473. data.maxForce
  474. );
  475. break;
  476. case 'hinge':
  477. constraint = new CANNON.HingeConstraint(
  478. this.el.body,
  479. data.target.body, {
  480. pivotA: pivot,
  481. pivotB: targetPivot,
  482. axisA: axis,
  483. axisB: targetAxis,
  484. maxForce: data.maxForce
  485. });
  486. break;
  487. case 'coneTwist':
  488. constraint = new CANNON.ConeTwistConstraint(
  489. this.el.body,
  490. data.target.body, {
  491. pivotA: pivot,
  492. pivotB: targetPivot,
  493. axisA: axis,
  494. axisB: targetAxis,
  495. maxForce: data.maxForce
  496. });
  497. break;
  498. case 'pointToPoint':
  499. constraint = new CANNON.PointToPointConstraint(
  500. this.el.body,
  501. pivot,
  502. data.target.body,
  503. targetPivot,
  504. data.maxForce);
  505. break;
  506. default:
  507. throw new Error('[constraint] Unexpected type: ' + data.type);
  508. }
  509. constraint.collideConnected = data.collideConnected;
  510. return constraint;
  511. }
  512. };
  513. },{"cannon":14}],8:[function(require,module,exports){
  514. module.exports = {
  515. 'velocity': require('./velocity'),
  516. 'quaternion': require('./quaternion'),
  517. registerAll: function (AFRAME) {
  518. if (this._registered) return;
  519. AFRAME = AFRAME || window.AFRAME;
  520. if (!AFRAME.components['velocity']) AFRAME.registerComponent('velocity', this.velocity);
  521. if (!AFRAME.components['quaternion']) AFRAME.registerComponent('quaternion', this.quaternion);
  522. this._registered = true;
  523. }
  524. };
  525. },{"./quaternion":9,"./velocity":10}],9:[function(require,module,exports){
  526. /**
  527. * Quaternion.
  528. *
  529. * Represents orientation of object in three dimensions. Similar to `rotation`
  530. * component, but avoids problems of gimbal lock.
  531. *
  532. * See: https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
  533. */
  534. module.exports = {
  535. schema: {type: 'vec4'},
  536. play: function () {
  537. var el = this.el,
  538. q = el.object3D.quaternion;
  539. if (el.hasAttribute('rotation')) {
  540. el.components.rotation.update();
  541. el.setAttribute('quaternion', {x: q.x, y: q.y, z: q.z, w: q.w});
  542. el.removeAttribute('rotation');
  543. this.update();
  544. }
  545. },
  546. update: function () {
  547. var data = this.data;
  548. this.el.object3D.quaternion.set(data.x, data.y, data.z, data.w);
  549. }
  550. };
  551. },{}],10:[function(require,module,exports){
  552. /**
  553. * Velocity, in m/s.
  554. */
  555. module.exports = {
  556. schema: {type: 'vec3'},
  557. init: function () {
  558. this.system = this.el.sceneEl.systems.physics;
  559. if (this.system) {
  560. this.system.addBehavior(this, this.system.Phase.RENDER);
  561. }
  562. },
  563. remove: function () {
  564. if (this.system) {
  565. this.system.removeBehavior(this, this.system.Phase.RENDER);
  566. }
  567. },
  568. tick: function (t, dt) {
  569. if (!dt) return;
  570. if (this.system) return;
  571. this.step(t, dt);
  572. },
  573. step: function (t, dt) {
  574. if (!dt) return;
  575. var physics = this.el.sceneEl.systems.physics || {data: {maxInterval: 1 / 60}},
  576. // TODO - There's definitely a bug with getComputedAttribute and el.data.
  577. velocity = this.el.getAttribute('velocity') || {x: 0, y: 0, z: 0},
  578. position = this.el.getAttribute('position') || {x: 0, y: 0, z: 0};
  579. dt = Math.min(dt, physics.data.maxInterval * 1000);
  580. this.el.setAttribute('position', {
  581. x: position.x + velocity.x * dt / 1000,
  582. y: position.y + velocity.y * dt / 1000,
  583. z: position.z + velocity.z * dt / 1000
  584. });
  585. }
  586. };
  587. },{}],11:[function(require,module,exports){
  588. module.exports = {
  589. GRAVITY: -9.8,
  590. MAX_INTERVAL: 4 / 60,
  591. ITERATIONS: 10,
  592. CONTACT_MATERIAL: {
  593. friction: 0.01,
  594. restitution: 0.3,
  595. contactEquationStiffness: 1e8,
  596. contactEquationRelaxation: 3,
  597. frictionEquationStiffness: 1e8,
  598. frictionEquationRegularization: 3
  599. }
  600. };
  601. },{}],12:[function(require,module,exports){
  602. var CANNON = require('cannon'),
  603. CONSTANTS = require('../constants'),
  604. C_GRAV = CONSTANTS.GRAVITY,
  605. C_MAT = CONSTANTS.CONTACT_MATERIAL;
  606. /**
  607. * Physics system.
  608. */
  609. module.exports = {
  610. schema: {
  611. gravity: { default: C_GRAV },
  612. iterations: { default: CONSTANTS.ITERATIONS },
  613. friction: { default: C_MAT.friction },
  614. restitution: { default: C_MAT.restitution },
  615. contactEquationStiffness: { default: C_MAT.contactEquationStiffness },
  616. contactEquationRelaxation: { default: C_MAT.contactEquationRelaxation },
  617. frictionEquationStiffness: { default: C_MAT.frictionEquationStiffness },
  618. frictionEquationRegularization: { default: C_MAT.frictionEquationRegularization },
  619. // Never step more than four frames at once. Effectively pauses the scene
  620. // when out of focus, and prevents weird "jumps" when focus returns.
  621. maxInterval: { default: 4 / 60 },
  622. // If true, show wireframes around physics bodies.
  623. debug: { default: false },
  624. },
  625. /**
  626. * Update phases, used to separate physics simulation from updates to A-Frame scene.
  627. * @enum {string}
  628. */
  629. Phase: {
  630. SIMULATE: 'sim',
  631. RENDER: 'render'
  632. },
  633. /**
  634. * Initializes the physics system.
  635. */
  636. init: function () {
  637. var data = this.data;
  638. // If true, show wireframes around physics bodies.
  639. this.debug = data.debug;
  640. this.children = {};
  641. this.children[this.Phase.SIMULATE] = [];
  642. this.children[this.Phase.RENDER] = [];
  643. this.listeners = {};
  644. this.world = new CANNON.World();
  645. this.world.quatNormalizeSkip = 0;
  646. this.world.quatNormalizeFast = false;
  647. // this.world.solver.setSpookParams(300,10);
  648. this.world.solver.iterations = data.iterations;
  649. this.world.gravity.set(0, data.gravity, 0);
  650. this.world.broadphase = new CANNON.NaiveBroadphase();
  651. this.material = new CANNON.Material({name: 'defaultMaterial'});
  652. this.contactMaterial = new CANNON.ContactMaterial(this.material, this.material, {
  653. friction: data.friction,
  654. restitution: data.restitution,
  655. contactEquationStiffness: data.contactEquationStiffness,
  656. contactEquationRelaxation: data.contactEquationRelaxation,
  657. frictionEquationStiffness: data.frictionEquationStiffness,
  658. frictionEquationRegularization: data.frictionEquationRegularization
  659. });
  660. this.world.addContactMaterial(this.contactMaterial);
  661. },
  662. /**
  663. * Updates the physics world on each tick of the A-Frame scene. It would be
  664. * entirely possible to separate the two – updating physics more or less
  665. * frequently than the scene – if greater precision or performance were
  666. * necessary.
  667. * @param {number} t
  668. * @param {number} dt
  669. */
  670. tick: function (t, dt) {
  671. if (!dt) return;
  672. this.world.step(Math.min(dt / 1000, this.data.maxInterval));
  673. var i;
  674. for (i = 0; i < this.children[this.Phase.SIMULATE].length; i++) {
  675. this.children[this.Phase.SIMULATE][i].step(t, dt);
  676. }
  677. for (i = 0; i < this.children[this.Phase.RENDER].length; i++) {
  678. this.children[this.Phase.RENDER][i].step(t, dt);
  679. }
  680. },
  681. /**
  682. * Adds a body to the scene, and binds collision events to the element.
  683. * @param {CANNON.Body} body
  684. */
  685. addBody: function (body) {
  686. this.listeners[body.id] = function (e) { body.el.emit('collide', e); };
  687. body.addEventListener('collide', this.listeners[body.id]);
  688. this.world.addBody(body);
  689. },
  690. /**
  691. * Removes a body, and its listeners, from the scene.
  692. * @param {CANNON.Body} body
  693. */
  694. removeBody: function (body) {
  695. body.removeEventListener('collide', this.listeners[body.id]);
  696. delete this.listeners[body.id];
  697. this.world.removeBody(body);
  698. },
  699. /**
  700. * Adds a component instance to the system, to be invoked on each tick during
  701. * the given phase.
  702. * @param {Component} component
  703. * @param {string} phase
  704. */
  705. addBehavior: function (component, phase) {
  706. this.children[phase].push(component);
  707. },
  708. /**
  709. * Removes a component instance from the system.
  710. * @param {Component} component
  711. * @param {string} phase
  712. */
  713. removeBehavior: function (component, phase) {
  714. this.children[phase].splice(this.children[phase].indexOf(component), 1);
  715. },
  716. /**
  717. * Sets an option on the physics system, affecting future simulation steps.
  718. * @param {string} opt
  719. * @param {mixed} value
  720. */
  721. update: function (previousData) {
  722. var data = this.data;
  723. if (data.debug !== previousData.debug) {
  724. console.warn('[physics] `debug` cannot be changed dynamically.');
  725. }
  726. if (data.maxInterval !== previousData.maxInterval); // noop;
  727. if (data.gravity !== previousData.gravity) this.world.gravity.set(0, data.gravity, 0);
  728. this.contactMaterial.friction = data.friction;
  729. this.contactMaterial.restitution = data.restitution;
  730. this.contactMaterial.contactEquationStiffness = data.contactEquationStiffness;
  731. this.contactMaterial.contactEquationRelaxation = data.contactEquationRelaxation;
  732. this.contactMaterial.frictionEquationStiffness = data.frictionEquationStiffness;
  733. this.contactMaterial.frictionEquationRegularization = data.frictionEquationRegularization;
  734. }
  735. };
  736. },{"../constants":11,"cannon":14}],13:[function(require,module,exports){
  737. module.exports={
  738. "_from": "github:donmccurdy/cannon.js#v0.6.2-dev1",
  739. "_id": "cannon@0.6.2",
  740. "_inBundle": false,
  741. "_integrity": "sha1-kuhwtr7Hd8jqU3mcndOx2tmf0RU=",
  742. "_location": "/cannon",
  743. "_phantomChildren": {},
  744. "_requested": {
  745. "type": "git",
  746. "raw": "cannon@github:donmccurdy/cannon.js#v0.6.2-dev1",
  747. "name": "cannon",
  748. "escapedName": "cannon",
  749. "rawSpec": "github:donmccurdy/cannon.js#v0.6.2-dev1",
  750. "saveSpec": "github:donmccurdy/cannon.js#v0.6.2-dev1",
  751. "fetchSpec": null,
  752. "gitCommittish": "v0.6.2-dev1"
  753. },
  754. "_requiredBy": [
  755. "/aframe-physics-system"
  756. ],
  757. "_resolved": "github:donmccurdy/cannon.js#022e8ba53fa83abf0ad8a0e4fd08623123838a17",
  758. "_spec": "cannon@github:donmccurdy/cannon.js#v0.6.2-dev1",
  759. "_where": "/Users/donmccurdy/Documents/Projects/aframe-extras/node_modules/aframe-physics-system",
  760. "author": {
  761. "name": "Stefan Hedman",
  762. "email": "schteppe@gmail.com",
  763. "url": "http://steffe.se"
  764. },
  765. "bugs": {
  766. "url": "https://github.com/schteppe/cannon.js/issues"
  767. },
  768. "bundleDependencies": false,
  769. "dependencies": {},
  770. "deprecated": false,
  771. "description": "A lightweight 3D physics engine written in JavaScript.",
  772. "devDependencies": {
  773. "browserify": "*",
  774. "grunt": "~0.4.0",
  775. "grunt-browserify": "^2.1.4",
  776. "grunt-contrib-concat": "~0.1.3",
  777. "grunt-contrib-jshint": "~0.1.1",
  778. "grunt-contrib-nodeunit": "^0.4.1",
  779. "grunt-contrib-uglify": "^0.5.1",
  780. "grunt-contrib-yuidoc": "^0.5.2",
  781. "jshint": "latest",
  782. "nodeunit": "^0.9.0",
  783. "uglify-js": "latest"
  784. },
  785. "engines": {
  786. "node": "*"
  787. },
  788. "homepage": "https://github.com/schteppe/cannon.js",
  789. "keywords": [
  790. "cannon.js",
  791. "cannon",
  792. "physics",
  793. "engine",
  794. "3d"
  795. ],
  796. "licenses": [
  797. {
  798. "type": "MIT"
  799. }
  800. ],
  801. "main": "./src/Cannon.js",
  802. "name": "cannon",
  803. "repository": {
  804. "type": "git",
  805. "url": "git+https://github.com/schteppe/cannon.js.git"
  806. },
  807. "version": "0.6.2"
  808. }
  809. },{}],14:[function(require,module,exports){
  810. // Export classes
  811. module.exports = {
  812. version : require('../package.json').version,
  813. AABB : require('./collision/AABB'),
  814. ArrayCollisionMatrix : require('./collision/ArrayCollisionMatrix'),
  815. Body : require('./objects/Body'),
  816. Box : require('./shapes/Box'),
  817. Broadphase : require('./collision/Broadphase'),
  818. Constraint : require('./constraints/Constraint'),
  819. ContactEquation : require('./equations/ContactEquation'),
  820. Narrowphase : require('./world/Narrowphase'),
  821. ConeTwistConstraint : require('./constraints/ConeTwistConstraint'),
  822. ContactMaterial : require('./material/ContactMaterial'),
  823. ConvexPolyhedron : require('./shapes/ConvexPolyhedron'),
  824. Cylinder : require('./shapes/Cylinder'),
  825. DistanceConstraint : require('./constraints/DistanceConstraint'),
  826. Equation : require('./equations/Equation'),
  827. EventTarget : require('./utils/EventTarget'),
  828. FrictionEquation : require('./equations/FrictionEquation'),
  829. GSSolver : require('./solver/GSSolver'),
  830. GridBroadphase : require('./collision/GridBroadphase'),
  831. Heightfield : require('./shapes/Heightfield'),
  832. HingeConstraint : require('./constraints/HingeConstraint'),
  833. LockConstraint : require('./constraints/LockConstraint'),
  834. Mat3 : require('./math/Mat3'),
  835. Material : require('./material/Material'),
  836. NaiveBroadphase : require('./collision/NaiveBroadphase'),
  837. ObjectCollisionMatrix : require('./collision/ObjectCollisionMatrix'),
  838. Pool : require('./utils/Pool'),
  839. Particle : require('./shapes/Particle'),
  840. Plane : require('./shapes/Plane'),
  841. PointToPointConstraint : require('./constraints/PointToPointConstraint'),
  842. Quaternion : require('./math/Quaternion'),
  843. Ray : require('./collision/Ray'),
  844. RaycastVehicle : require('./objects/RaycastVehicle'),
  845. RaycastResult : require('./collision/RaycastResult'),
  846. RigidVehicle : require('./objects/RigidVehicle'),
  847. RotationalEquation : require('./equations/RotationalEquation'),
  848. RotationalMotorEquation : require('./equations/RotationalMotorEquation'),
  849. SAPBroadphase : require('./collision/SAPBroadphase'),
  850. SPHSystem : require('./objects/SPHSystem'),
  851. Shape : require('./shapes/Shape'),
  852. Solver : require('./solver/Solver'),
  853. Sphere : require('./shapes/Sphere'),
  854. SplitSolver : require('./solver/SplitSolver'),
  855. Spring : require('./objects/Spring'),
  856. Transform : require('./math/Transform'),
  857. Trimesh : require('./shapes/Trimesh'),
  858. Vec3 : require('./math/Vec3'),
  859. Vec3Pool : require('./utils/Vec3Pool'),
  860. World : require('./world/World'),
  861. };
  862. },{"../package.json":13,"./collision/AABB":15,"./collision/ArrayCollisionMatrix":16,"./collision/Broadphase":17,"./collision/GridBroadphase":18,"./collision/NaiveBroadphase":19,"./collision/ObjectCollisionMatrix":20,"./collision/Ray":22,"./collision/RaycastResult":23,"./collision/SAPBroadphase":24,"./constraints/ConeTwistConstraint":25,"./constraints/Constraint":26,"./constraints/DistanceConstraint":27,"./constraints/HingeConstraint":28,"./constraints/LockConstraint":29,"./constraints/PointToPointConstraint":30,"./equations/ContactEquation":32,"./equations/Equation":33,"./equations/FrictionEquation":34,"./equations/RotationalEquation":35,"./equations/RotationalMotorEquation":36,"./material/ContactMaterial":37,"./material/Material":38,"./math/Mat3":40,"./math/Quaternion":41,"./math/Transform":42,"./math/Vec3":43,"./objects/Body":44,"./objects/RaycastVehicle":45,"./objects/RigidVehicle":46,"./objects/SPHSystem":47,"./objects/Spring":48,"./shapes/Box":50,"./shapes/ConvexPolyhedron":51,"./shapes/Cylinder":52,"./shapes/Heightfield":53,"./shapes/Particle":54,"./shapes/Plane":55,"./shapes/Shape":56,"./shapes/Sphere":57,"./shapes/Trimesh":58,"./solver/GSSolver":59,"./solver/Solver":60,"./solver/SplitSolver":61,"./utils/EventTarget":62,"./utils/Pool":64,"./utils/Vec3Pool":67,"./world/Narrowphase":68,"./world/World":69}],15:[function(require,module,exports){
  863. var Vec3 = require('../math/Vec3');
  864. var Utils = require('../utils/Utils');
  865. module.exports = AABB;
  866. /**
  867. * Axis aligned bounding box class.
  868. * @class AABB
  869. * @constructor
  870. * @param {Object} [options]
  871. * @param {Vec3} [options.upperBound]
  872. * @param {Vec3} [options.lowerBound]
  873. */
  874. function AABB(options){
  875. options = options || {};
  876. /**
  877. * The lower bound of the bounding box.
  878. * @property lowerBound
  879. * @type {Vec3}
  880. */
  881. this.lowerBound = new Vec3();
  882. if(options.lowerBound){
  883. this.lowerBound.copy(options.lowerBound);
  884. }
  885. /**
  886. * The upper bound of the bounding box.
  887. * @property upperBound
  888. * @type {Vec3}
  889. */
  890. this.upperBound = new Vec3();
  891. if(options.upperBound){
  892. this.upperBound.copy(options.upperBound);
  893. }
  894. }
  895. var tmp = new Vec3();
  896. /**
  897. * Set the AABB bounds from a set of points.
  898. * @method setFromPoints
  899. * @param {Array} points An array of Vec3's.
  900. * @param {Vec3} position
  901. * @param {Quaternion} quaternion
  902. * @param {number} skinSize
  903. * @return {AABB} The self object
  904. */
  905. AABB.prototype.setFromPoints = function(points, position, quaternion, skinSize){
  906. var l = this.lowerBound,
  907. u = this.upperBound,
  908. q = quaternion;
  909. // Set to the first point
  910. l.copy(points[0]);
  911. if(q){
  912. q.vmult(l, l);
  913. }
  914. u.copy(l);
  915. for(var i = 1; i<points.length; i++){
  916. var p = points[i];
  917. if(q){
  918. q.vmult(p, tmp);
  919. p = tmp;
  920. }
  921. if(p.x > u.x){ u.x = p.x; }
  922. if(p.x < l.x){ l.x = p.x; }
  923. if(p.y > u.y){ u.y = p.y; }
  924. if(p.y < l.y){ l.y = p.y; }
  925. if(p.z > u.z){ u.z = p.z; }
  926. if(p.z < l.z){ l.z = p.z; }
  927. }
  928. // Add offset
  929. if (position) {
  930. position.vadd(l, l);
  931. position.vadd(u, u);
  932. }
  933. if(skinSize){
  934. l.x -= skinSize;
  935. l.y -= skinSize;
  936. l.z -= skinSize;
  937. u.x += skinSize;
  938. u.y += skinSize;
  939. u.z += skinSize;
  940. }
  941. return this;
  942. };
  943. /**
  944. * Copy bounds from an AABB to this AABB
  945. * @method copy
  946. * @param {AABB} aabb Source to copy from
  947. * @return {AABB} The this object, for chainability
  948. */
  949. AABB.prototype.copy = function(aabb){
  950. this.lowerBound.copy(aabb.lowerBound);
  951. this.upperBound.copy(aabb.upperBound);
  952. return this;
  953. };
  954. /**
  955. * Clone an AABB
  956. * @method clone
  957. */
  958. AABB.prototype.clone = function(){
  959. return new AABB().copy(this);
  960. };
  961. /**
  962. * Extend this AABB so that it covers the given AABB too.
  963. * @method extend
  964. * @param {AABB} aabb
  965. */
  966. AABB.prototype.extend = function(aabb){
  967. this.lowerBound.x = Math.min(this.lowerBound.x, aabb.lowerBound.x);
  968. this.upperBound.x = Math.max(this.upperBound.x, aabb.upperBound.x);
  969. this.lowerBound.y = Math.min(this.lowerBound.y, aabb.lowerBound.y);
  970. this.upperBound.y = Math.max(this.upperBound.y, aabb.upperBound.y);
  971. this.lowerBound.z = Math.min(this.lowerBound.z, aabb.lowerBound.z);
  972. this.upperBound.z = Math.max(this.upperBound.z, aabb.upperBound.z);
  973. };
  974. /**
  975. * Returns true if the given AABB overlaps this AABB.
  976. * @method overlaps
  977. * @param {AABB} aabb
  978. * @return {Boolean}
  979. */
  980. AABB.prototype.overlaps = function(aabb){
  981. var l1 = this.lowerBound,
  982. u1 = this.upperBound,
  983. l2 = aabb.lowerBound,
  984. u2 = aabb.upperBound;
  985. // l2 u2
  986. // |---------|
  987. // |--------|
  988. // l1 u1
  989. var overlapsX = ((l2.x <= u1.x && u1.x <= u2.x) || (l1.x <= u2.x && u2.x <= u1.x));
  990. var overlapsY = ((l2.y <= u1.y && u1.y <= u2.y) || (l1.y <= u2.y && u2.y <= u1.y));
  991. var overlapsZ = ((l2.z <= u1.z && u1.z <= u2.z) || (l1.z <= u2.z && u2.z <= u1.z));
  992. return overlapsX && overlapsY && overlapsZ;
  993. };
  994. // Mostly for debugging
  995. AABB.prototype.volume = function(){
  996. var l = this.lowerBound,
  997. u = this.upperBound;
  998. return (u.x - l.x) * (u.y - l.y) * (u.z - l.z);
  999. };
  1000. /**
  1001. * Returns true if the given AABB is fully contained in this AABB.
  1002. * @method contains
  1003. * @param {AABB} aabb
  1004. * @return {Boolean}
  1005. */
  1006. AABB.prototype.contains = function(aabb){
  1007. var l1 = this.lowerBound,
  1008. u1 = this.upperBound,
  1009. l2 = aabb.lowerBound,
  1010. u2 = aabb.upperBound;
  1011. // l2 u2
  1012. // |---------|
  1013. // |---------------|
  1014. // l1 u1
  1015. return (
  1016. (l1.x <= l2.x && u1.x >= u2.x) &&
  1017. (l1.y <= l2.y && u1.y >= u2.y) &&
  1018. (l1.z <= l2.z && u1.z >= u2.z)
  1019. );
  1020. };
  1021. /**
  1022. * @method getCorners
  1023. * @param {Vec3} a
  1024. * @param {Vec3} b
  1025. * @param {Vec3} c
  1026. * @param {Vec3} d
  1027. * @param {Vec3} e
  1028. * @param {Vec3} f
  1029. * @param {Vec3} g
  1030. * @param {Vec3} h
  1031. */
  1032. AABB.prototype.getCorners = function(a, b, c, d, e, f, g, h){
  1033. var l = this.lowerBound,
  1034. u = this.upperBound;
  1035. a.copy(l);
  1036. b.set( u.x, l.y, l.z );
  1037. c.set( u.x, u.y, l.z );
  1038. d.set( l.x, u.y, u.z );
  1039. e.set( u.x, l.y, l.z );
  1040. f.set( l.x, u.y, l.z );
  1041. g.set( l.x, l.y, u.z );
  1042. h.copy(u);
  1043. };
  1044. var transformIntoFrame_corners = [
  1045. new Vec3(),
  1046. new Vec3(),
  1047. new Vec3(),
  1048. new Vec3(),
  1049. new Vec3(),
  1050. new Vec3(),
  1051. new Vec3(),
  1052. new Vec3()
  1053. ];
  1054. /**
  1055. * Get the representation of an AABB in another frame.
  1056. * @method toLocalFrame
  1057. * @param {Transform} frame
  1058. * @param {AABB} target
  1059. * @return {AABB} The "target" AABB object.
  1060. */
  1061. AABB.prototype.toLocalFrame = function(frame, target){
  1062. var corners = transformIntoFrame_corners;
  1063. var a = corners[0];
  1064. var b = corners[1];
  1065. var c = corners[2];
  1066. var d = corners[3];
  1067. var e = corners[4];
  1068. var f = corners[5];
  1069. var g = corners[6];
  1070. var h = corners[7];
  1071. // Get corners in current frame
  1072. this.getCorners(a, b, c, d, e, f, g, h);
  1073. // Transform them to new local frame
  1074. for(var i=0; i !== 8; i++){
  1075. var corner = corners[i];
  1076. frame.pointToLocal(corner, corner);
  1077. }
  1078. return target.setFromPoints(corners);
  1079. };
  1080. /**
  1081. * Get the representation of an AABB in the global frame.
  1082. * @method toWorldFrame
  1083. * @param {Transform} frame
  1084. * @param {AABB} target
  1085. * @return {AABB} The "target" AABB object.
  1086. */
  1087. AABB.prototype.toWorldFrame = function(frame, target){
  1088. var corners = transformIntoFrame_corners;
  1089. var a = corners[0];
  1090. var b = corners[1];
  1091. var c = corners[2];
  1092. var d = corners[3];
  1093. var e = corners[4];
  1094. var f = corners[5];
  1095. var g = corners[6];
  1096. var h = corners[7];
  1097. // Get corners in current frame
  1098. this.getCorners(a, b, c, d, e, f, g, h);
  1099. // Transform them to new local frame
  1100. for(var i=0; i !== 8; i++){
  1101. var corner = corners[i];
  1102. frame.pointToWorld(corner, corner);
  1103. }
  1104. return target.setFromPoints(corners);
  1105. };
  1106. /**
  1107. * Check if the AABB is hit by a ray.
  1108. * @param {Ray} ray
  1109. * @return {number}
  1110. */
  1111. AABB.prototype.overlapsRay = function(ray){
  1112. var t = 0;
  1113. // ray.direction is unit direction vector of ray
  1114. var dirFracX = 1 / ray._direction.x;
  1115. var dirFracY = 1 / ray._direction.y;
  1116. var dirFracZ = 1 / ray._direction.z;
  1117. // this.lowerBound is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
  1118. var t1 = (this.lowerBound.x - ray.from.x) * dirFracX;
  1119. var t2 = (this.upperBound.x - ray.from.x) * dirFracX;
  1120. var t3 = (this.lowerBound.y - ray.from.y) * dirFracY;
  1121. var t4 = (this.upperBound.y - ray.from.y) * dirFracY;
  1122. var t5 = (this.lowerBound.z - ray.from.z) * dirFracZ;
  1123. var t6 = (this.upperBound.z - ray.from.z) * dirFracZ;
  1124. // var tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)));
  1125. // var tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)));
  1126. var tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)), Math.min(t5, t6));
  1127. var tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)), Math.max(t5, t6));
  1128. // if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us
  1129. if (tmax < 0){
  1130. //t = tmax;
  1131. return false;
  1132. }
  1133. // if tmin > tmax, ray doesn't intersect AABB
  1134. if (tmin > tmax){
  1135. //t = tmax;
  1136. return false;
  1137. }
  1138. return true;
  1139. };
  1140. },{"../math/Vec3":43,"../utils/Utils":66}],16:[function(require,module,exports){
  1141. module.exports = ArrayCollisionMatrix;
  1142. /**
  1143. * Collision "matrix". It's actually a triangular-shaped array of whether two bodies are touching this step, for reference next step
  1144. * @class ArrayCollisionMatrix
  1145. * @constructor
  1146. */
  1147. function ArrayCollisionMatrix() {
  1148. /**
  1149. * The matrix storage
  1150. * @property matrix
  1151. * @type {Array}
  1152. */
  1153. this.matrix = [];
  1154. }
  1155. /**
  1156. * Get an element
  1157. * @method get
  1158. * @param {Number} i
  1159. * @param {Number} j
  1160. * @return {Number}
  1161. */
  1162. ArrayCollisionMatrix.prototype.get = function(i, j) {
  1163. i = i.index;
  1164. j = j.index;
  1165. if (j > i) {
  1166. var temp = j;
  1167. j = i;
  1168. i = temp;
  1169. }
  1170. return this.matrix[(i*(i + 1)>>1) + j-1];
  1171. };
  1172. /**
  1173. * Set an element
  1174. * @method set
  1175. * @param {Number} i
  1176. * @param {Number} j
  1177. * @param {Number} value
  1178. */
  1179. ArrayCollisionMatrix.prototype.set = function(i, j, value) {
  1180. i = i.index;
  1181. j = j.index;
  1182. if (j > i) {
  1183. var temp = j;
  1184. j = i;
  1185. i = temp;
  1186. }
  1187. this.matrix[(i*(i + 1)>>1) + j-1] = value ? 1 : 0;
  1188. };
  1189. /**
  1190. * Sets all elements to zero
  1191. * @method reset
  1192. */
  1193. ArrayCollisionMatrix.prototype.reset = function() {
  1194. for (var i=0, l=this.matrix.length; i!==l; i++) {
  1195. this.matrix[i]=0;
  1196. }
  1197. };
  1198. /**
  1199. * Sets the max number of objects
  1200. * @method setNumObjects
  1201. * @param {Number} n
  1202. */
  1203. ArrayCollisionMatrix.prototype.setNumObjects = function(n) {
  1204. this.matrix.length = n*(n-1)>>1;
  1205. };
  1206. },{}],17:[function(require,module,exports){
  1207. var Body = require('../objects/Body');
  1208. var Vec3 = require('../math/Vec3');
  1209. var Quaternion = require('../math/Quaternion');
  1210. var Shape = require('../shapes/Shape');
  1211. var Plane = require('../shapes/Plane');
  1212. module.exports = Broadphase;
  1213. /**
  1214. * Base class for broadphase implementations
  1215. * @class Broadphase
  1216. * @constructor
  1217. * @author schteppe
  1218. */
  1219. function Broadphase(){
  1220. /**
  1221. * The world to search for collisions in.
  1222. * @property world
  1223. * @type {World}
  1224. */
  1225. this.world = null;
  1226. /**
  1227. * If set to true, the broadphase uses bounding boxes for intersection test, else it uses bounding spheres.
  1228. * @property useBoundingBoxes
  1229. * @type {Boolean}
  1230. */
  1231. this.useBoundingBoxes = false;
  1232. /**
  1233. * Set to true if the objects in the world moved.
  1234. * @property {Boolean} dirty
  1235. */
  1236. this.dirty = true;
  1237. }
  1238. /**
  1239. * Get the collision pairs from the world
  1240. * @method collisionPairs
  1241. * @param {World} world The world to search in
  1242. * @param {Array} p1 Empty array to be filled with body objects
  1243. * @param {Array} p2 Empty array to be filled with body objects
  1244. */
  1245. Broadphase.prototype.collisionPairs = function(world,p1,p2){
  1246. throw new Error("collisionPairs not implemented for this BroadPhase class!");
  1247. };
  1248. /**
  1249. * Check if a body pair needs to be intersection tested at all.
  1250. * @method needBroadphaseCollision
  1251. * @param {Body} bodyA
  1252. * @param {Body} bodyB
  1253. * @return {bool}
  1254. */
  1255. Broadphase.prototype.needBroadphaseCollision = function(bodyA,bodyB){
  1256. // Check collision filter masks
  1257. if( (bodyA.collisionFilterGroup & bodyB.collisionFilterMask)===0 || (bodyB.collisionFilterGroup & bodyA.collisionFilterMask)===0){
  1258. return false;
  1259. }
  1260. // Check types
  1261. if(((bodyA.type & Body.STATIC)!==0 || bodyA.sleepState === Body.SLEEPING) &&
  1262. ((bodyB.type & Body.STATIC)!==0 || bodyB.sleepState === Body.SLEEPING)) {
  1263. // Both bodies are static or sleeping. Skip.
  1264. return false;
  1265. }
  1266. return true;
  1267. };
  1268. /**
  1269. * Check if the bounding volumes of two bodies intersect.
  1270. * @method intersectionTest
  1271. * @param {Body} bodyA
  1272. * @param {Body} bodyB
  1273. * @param {array} pairs1
  1274. * @param {array} pairs2
  1275. */
  1276. Broadphase.prototype.intersectionTest = function(bodyA, bodyB, pairs1, pairs2){
  1277. if(this.useBoundingBoxes){
  1278. this.doBoundingBoxBroadphase(bodyA,bodyB,pairs1,pairs2);
  1279. } else {
  1280. this.doBoundingSphereBroadphase(bodyA,bodyB,pairs1,pairs2);
  1281. }
  1282. };
  1283. /**
  1284. * Check if the bounding spheres of two bodies are intersecting.
  1285. * @method doBoundingSphereBroadphase
  1286. * @param {Body} bodyA
  1287. * @param {Body} bodyB
  1288. * @param {Array} pairs1 bodyA is appended to this array if intersection
  1289. * @param {Array} pairs2 bodyB is appended to this array if intersection
  1290. */
  1291. var Broadphase_collisionPairs_r = new Vec3(), // Temp objects
  1292. Broadphase_collisionPairs_normal = new Vec3(),
  1293. Broadphase_collisionPairs_quat = new Quaternion(),
  1294. Broadphase_collisionPairs_relpos = new Vec3();
  1295. Broadphase.prototype.doBoundingSphereBroadphase = function(bodyA,bodyB,pairs1,pairs2){
  1296. var r = Broadphase_collisionPairs_r;
  1297. bodyB.position.vsub(bodyA.position,r);
  1298. var boundingRadiusSum2 = Math.pow(bodyA.boundingRadius + bodyB.boundingRadius, 2);
  1299. var norm2 = r.norm2();
  1300. if(norm2 < boundingRadiusSum2){
  1301. pairs1.push(bodyA);
  1302. pairs2.push(bodyB);
  1303. }
  1304. };
  1305. /**
  1306. * Check if the bounding boxes of two bodies are intersecting.
  1307. * @method doBoundingBoxBroadphase
  1308. * @param {Body} bodyA
  1309. * @param {Body} bodyB
  1310. * @param {Array} pairs1
  1311. * @param {Array} pairs2
  1312. */
  1313. Broadphase.prototype.doBoundingBoxBroadphase = function(bodyA,bodyB,pairs1,pairs2){
  1314. if(bodyA.aabbNeedsUpdate){
  1315. bodyA.computeAABB();
  1316. }
  1317. if(bodyB.aabbNeedsUpdate){
  1318. bodyB.computeAABB();
  1319. }
  1320. // Check AABB / AABB
  1321. if(bodyA.aabb.overlaps(bodyB.aabb)){
  1322. pairs1.push(bodyA);
  1323. pairs2.push(bodyB);
  1324. }
  1325. };
  1326. /**
  1327. * Removes duplicate pairs from the pair arrays.
  1328. * @method makePairsUnique
  1329. * @param {Array} pairs1
  1330. * @param {Array} pairs2
  1331. */
  1332. var Broadphase_makePairsUnique_temp = { keys:[] },
  1333. Broadphase_makePairsUnique_p1 = [],
  1334. Broadphase_makePairsUnique_p2 = [];
  1335. Broadphase.prototype.makePairsUnique = function(pairs1,pairs2){
  1336. var t = Broadphase_makePairsUnique_temp,
  1337. p1 = Broadphase_makePairsUnique_p1,
  1338. p2 = Broadphase_makePairsUnique_p2,
  1339. N = pairs1.length;
  1340. for(var i=0; i!==N; i++){
  1341. p1[i] = pairs1[i];
  1342. p2[i] = pairs2[i];
  1343. }
  1344. pairs1.length = 0;
  1345. pairs2.length = 0;
  1346. for(var i=0; i!==N; i++){
  1347. var id1 = p1[i].id,
  1348. id2 = p2[i].id;
  1349. var key = id1 < id2 ? id1+","+id2 : id2+","+id1;
  1350. t[key] = i;
  1351. t.keys.push(key);
  1352. }
  1353. for(var i=0; i!==t.keys.length; i++){
  1354. var key = t.keys.pop(),
  1355. pairIndex = t[key];
  1356. pairs1.push(p1[pairIndex]);
  1357. pairs2.push(p2[pairIndex]);
  1358. delete t[key];
  1359. }
  1360. };
  1361. /**
  1362. * To be implemented by subcasses
  1363. * @method setWorld
  1364. * @param {World} world
  1365. */
  1366. Broadphase.prototype.setWorld = function(world){
  1367. };
  1368. /**
  1369. * Check if the bounding spheres of two bodies overlap.
  1370. * @method boundingSphereCheck
  1371. * @param {Body} bodyA
  1372. * @param {Body} bodyB
  1373. * @return {boolean}
  1374. */
  1375. var bsc_dist = new Vec3();
  1376. Broadphase.boundingSphereCheck = function(bodyA,bodyB){
  1377. var dist = bsc_dist;
  1378. bodyA.position.vsub(bodyB.position,dist);
  1379. return Math.pow(bodyA.shape.boundingSphereRadius + bodyB.shape.boundingSphereRadius,2) > dist.norm2();
  1380. };
  1381. /**
  1382. * Returns all the bodies within the AABB.
  1383. * @method aabbQuery
  1384. * @param {World} world
  1385. * @param {AABB} aabb
  1386. * @param {array} result An array to store resulting bodies in.
  1387. * @return {array}
  1388. */
  1389. Broadphase.prototype.aabbQuery = function(world, aabb, result){
  1390. console.warn('.aabbQuery is not implemented in this Broadphase subclass.');
  1391. return [];
  1392. };
  1393. },{"../math/Quaternion":41,"../math/Vec3":43,"../objects/Body":44,"../shapes/Plane":55,"../shapes/Shape":56}],18:[function(require,module,exports){
  1394. module.exports = GridBroadphase;
  1395. var Broadphase = require('./Broadphase');
  1396. var Vec3 = require('../math/Vec3');
  1397. var Shape = require('../shapes/Shape');
  1398. /**
  1399. * Axis aligned uniform grid broadphase.
  1400. * @class GridBroadphase
  1401. * @constructor
  1402. * @extends Broadphase
  1403. * @todo Needs support for more than just planes and spheres.
  1404. * @param {Vec3} aabbMin
  1405. * @param {Vec3} aabbMax
  1406. * @param {Number} nx Number of boxes along x
  1407. * @param {Number} ny Number of boxes along y
  1408. * @param {Number} nz Number of boxes along z
  1409. */
  1410. function GridBroadphase(aabbMin,aabbMax,nx,ny,nz){
  1411. Broadphase.apply(this);
  1412. this.nx = nx || 10;
  1413. this.ny = ny || 10;
  1414. this.nz = nz || 10;
  1415. this.aabbMin = aabbMin || new Vec3(100,100,100);
  1416. this.aabbMax = aabbMax || new Vec3(-100,-100,-100);
  1417. var nbins = this.nx * this.ny * this.nz;
  1418. if (nbins <= 0) {
  1419. throw "GridBroadphase: Each dimension's n must be >0";
  1420. }
  1421. this.bins = [];
  1422. this.binLengths = []; //Rather than continually resizing arrays (thrashing the memory), just record length and allow them to grow
  1423. this.bins.length = nbins;
  1424. this.binLengths.length = nbins;
  1425. for (var i=0;i<nbins;i++) {
  1426. this.bins[i]=[];
  1427. this.binLengths[i]=0;
  1428. }
  1429. }
  1430. GridBroadphase.prototype = new Broadphase();
  1431. GridBroadphase.prototype.constructor = GridBroadphase;
  1432. /**
  1433. * Get all the collision pairs in the physics world
  1434. * @method collisionPairs
  1435. * @param {World} world
  1436. * @param {Array} pairs1
  1437. * @param {Array} pairs2
  1438. */
  1439. var GridBroadphase_collisionPairs_d = new Vec3();
  1440. var GridBroadphase_collisionPairs_binPos = new Vec3();
  1441. GridBroadphase.prototype.collisionPairs = function(world,pairs1,pairs2){
  1442. var N = world.numObjects(),
  1443. bodies = world.bodies;
  1444. var max = this.aabbMax,
  1445. min = this.aabbMin,
  1446. nx = this.nx,
  1447. ny = this.ny,
  1448. nz = this.nz;
  1449. var xstep = ny*nz;
  1450. var ystep = nz;
  1451. var zstep = 1;
  1452. var xmax = max.x,
  1453. ymax = max.y,
  1454. zmax = max.z,
  1455. xmin = min.x,
  1456. ymin = min.y,
  1457. zmin = min.z;
  1458. var xmult = nx / (xmax-xmin),
  1459. ymult = ny / (ymax-ymin),
  1460. zmult = nz / (zmax-zmin);
  1461. var binsizeX = (xmax - xmin) / nx,
  1462. binsizeY = (ymax - ymin) / ny,
  1463. binsizeZ = (zmax - zmin) / nz;
  1464. var binRadius = Math.sqrt(binsizeX*binsizeX + binsizeY*binsizeY + binsizeZ*binsizeZ) * 0.5;
  1465. var types = Shape.types;
  1466. var SPHERE = types.SPHERE,
  1467. PLANE = types.PLANE,
  1468. BOX = types.BOX,
  1469. COMPOUND = types.COMPOUND,
  1470. CONVEXPOLYHEDRON = types.CONVEXPOLYHEDRON;
  1471. var bins=this.bins,
  1472. binLengths=this.binLengths,
  1473. Nbins=this.bins.length;
  1474. // Reset bins
  1475. for(var i=0; i!==Nbins; i++){
  1476. binLengths[i] = 0;
  1477. }
  1478. var ceil = Math.ceil;
  1479. var min = Math.min;
  1480. var max = Math.max;
  1481. function addBoxToBins(x0,y0,z0,x1,y1,z1,bi) {
  1482. var xoff0 = ((x0 - xmin) * xmult)|0,
  1483. yoff0 = ((y0 - ymin) * ymult)|0,
  1484. zoff0 = ((z0 - zmin) * zmult)|0,
  1485. xoff1 = ceil((x1 - xmin) * xmult),
  1486. yoff1 = ceil((y1 - ymin) * ymult),
  1487. zoff1 = ceil((z1 - zmin) * zmult);
  1488. if (xoff0 < 0) { xoff0 = 0; } else if (xoff0 >= nx) { xoff0 = nx - 1; }
  1489. if (yoff0 < 0) { yoff0 = 0; } else if (yoff0 >= ny) { yoff0 = ny - 1; }
  1490. if (zoff0 < 0) { zoff0 = 0; } else if (zoff0 >= nz) { zoff0 = nz - 1; }
  1491. if (xoff1 < 0) { xoff1 = 0; } else if (xoff1 >= nx) { xoff1 = nx - 1; }
  1492. if (yoff1 < 0) { yoff1 = 0; } else if (yoff1 >= ny) { yoff1 = ny - 1; }
  1493. if (zoff1 < 0) { zoff1 = 0; } else if (zoff1 >= nz) { zoff1 = nz - 1; }
  1494. xoff0 *= xstep;
  1495. yoff0 *= ystep;
  1496. zoff0 *= zstep;
  1497. xoff1 *= xstep;
  1498. yoff1 *= ystep;
  1499. zoff1 *= zstep;
  1500. for (var xoff = xoff0; xoff <= xoff1; xoff += xstep) {
  1501. for (var yoff = yoff0; yoff <= yoff1; yoff += ystep) {
  1502. for (var zoff = zoff0; zoff <= zoff1; zoff += zstep) {
  1503. var idx = xoff+yoff+zoff;
  1504. bins[idx][binLengths[idx]++] = bi;
  1505. }
  1506. }
  1507. }
  1508. }
  1509. // Put all bodies into the bins
  1510. for(var i=0; i!==N; i++){
  1511. var bi = bodies[i];
  1512. var si = bi.shape;
  1513. switch(si.type){
  1514. case SPHERE:
  1515. // Put in bin
  1516. // check if overlap with other bins
  1517. var x = bi.position.x,
  1518. y = bi.position.y,
  1519. z = bi.position.z;
  1520. var r = si.radius;
  1521. addBoxToBins(x-r, y-r, z-r, x+r, y+r, z+r, bi);
  1522. break;
  1523. case PLANE:
  1524. if(si.worldNormalNeedsUpdate){
  1525. si.computeWorldNormal(bi.quaternion);
  1526. }
  1527. var planeNormal = si.worldNormal;
  1528. //Relative position from origin of plane object to the first bin
  1529. //Incremented as we iterate through the bins
  1530. var xreset = xmin + binsizeX*0.5 - bi.position.x,
  1531. yreset = ymin + binsizeY*0.5 - bi.position.y,
  1532. zreset = zmin + binsizeZ*0.5 - bi.position.z;
  1533. var d = GridBroadphase_collisionPairs_d;
  1534. d.set(xreset, yreset, zreset);
  1535. for (var xi = 0, xoff = 0; xi !== nx; xi++, xoff += xstep, d.y = yreset, d.x += binsizeX) {
  1536. for (var yi = 0, yoff = 0; yi !== ny; yi++, yoff += ystep, d.z = zreset, d.y += binsizeY) {
  1537. for (var zi = 0, zoff = 0; zi !== nz; zi++, zoff += zstep, d.z += binsizeZ) {
  1538. if (d.dot(planeNormal) < binRadius) {
  1539. var idx = xoff + yoff + zoff;
  1540. bins[idx][binLengths[idx]++] = bi;
  1541. }
  1542. }
  1543. }
  1544. }
  1545. break;
  1546. default:
  1547. if (bi.aabbNeedsUpdate) {
  1548. bi.computeAABB();
  1549. }
  1550. addBoxToBins(
  1551. bi.aabb.lowerBound.x,
  1552. bi.aabb.lowerBound.y,
  1553. bi.aabb.lowerBound.z,
  1554. bi.aabb.upperBound.x,
  1555. bi.aabb.upperBound.y,
  1556. bi.aabb.upperBound.z,
  1557. bi);
  1558. break;
  1559. }
  1560. }
  1561. // Check each bin
  1562. for(var i=0; i!==Nbins; i++){
  1563. var binLength = binLengths[i];
  1564. //Skip bins with no potential collisions
  1565. if (binLength > 1) {
  1566. var bin = bins[i];
  1567. // Do N^2 broadphase inside
  1568. for(var xi=0; xi!==binLength; xi++){
  1569. var bi = bin[xi];
  1570. for(var yi=0; yi!==xi; yi++){
  1571. var bj = bin[yi];
  1572. if(this.needBroadphaseCollision(bi,bj)){
  1573. this.intersectionTest(bi,bj,pairs1,pairs2);
  1574. }
  1575. }
  1576. }
  1577. }
  1578. }
  1579. // for (var zi = 0, zoff=0; zi < nz; zi++, zoff+= zstep) {
  1580. // console.log("layer "+zi);
  1581. // for (var yi = 0, yoff=0; yi < ny; yi++, yoff += ystep) {
  1582. // var row = '';
  1583. // for (var xi = 0, xoff=0; xi < nx; xi++, xoff += xstep) {
  1584. // var idx = xoff + yoff + zoff;
  1585. // row += ' ' + binLengths[idx];
  1586. // }
  1587. // console.log(row);
  1588. // }
  1589. // }
  1590. this.makePairsUnique(pairs1,pairs2);
  1591. };
  1592. },{"../math/Vec3":43,"../shapes/Shape":56,"./Broadphase":17}],19:[function(require,module,exports){
  1593. module.exports = NaiveBroadphase;
  1594. var Broadphase = require('./Broadphase');
  1595. var AABB = require('./AABB');
  1596. /**
  1597. * Naive broadphase implementation, used in lack of better ones.
  1598. * @class NaiveBroadphase
  1599. * @constructor
  1600. * @description The naive broadphase looks at all possible pairs without restriction, therefore it has complexity N^2 (which is bad)
  1601. * @extends Broadphase
  1602. */
  1603. function NaiveBroadphase(){
  1604. Broadphase.apply(this);
  1605. }
  1606. NaiveBroadphase.prototype = new Broadphase();
  1607. NaiveBroadphase.prototype.constructor = NaiveBroadphase;
  1608. /**
  1609. * Get all the collision pairs in the physics world
  1610. * @method collisionPairs
  1611. * @param {World} world
  1612. * @param {Array} pairs1
  1613. * @param {Array} pairs2
  1614. */
  1615. NaiveBroadphase.prototype.collisionPairs = function(world,pairs1,pairs2){
  1616. var bodies = world.bodies,
  1617. n = bodies.length,
  1618. i,j,bi,bj;
  1619. // Naive N^2 ftw!
  1620. for(i=0; i!==n; i++){
  1621. for(j=0; j!==i; j++){
  1622. bi = bodies[i];
  1623. bj = bodies[j];
  1624. if(!this.needBroadphaseCollision(bi,bj)){
  1625. continue;
  1626. }
  1627. this.intersectionTest(bi,bj,pairs1,pairs2);
  1628. }
  1629. }
  1630. };
  1631. var tmpAABB = new AABB();
  1632. /**
  1633. * Returns all the bodies within an AABB.
  1634. * @method aabbQuery
  1635. * @param {World} world
  1636. * @param {AABB} aabb
  1637. * @param {array} result An array to store resulting bodies in.
  1638. * @return {array}
  1639. */
  1640. NaiveBroadphase.prototype.aabbQuery = function(world, aabb, result){
  1641. result = result || [];
  1642. for(var i = 0; i < world.bodies.length; i++){
  1643. var b = world.bodies[i];
  1644. if(b.aabbNeedsUpdate){
  1645. b.computeAABB();
  1646. }
  1647. // Ugly hack until Body gets aabb
  1648. if(b.aabb.overlaps(aabb)){
  1649. result.push(b);
  1650. }
  1651. }
  1652. return result;
  1653. };
  1654. },{"./AABB":15,"./Broadphase":17}],20:[function(require,module,exports){
  1655. module.exports = ObjectCollisionMatrix;
  1656. /**
  1657. * Records what objects are colliding with each other
  1658. * @class ObjectCollisionMatrix
  1659. * @constructor
  1660. */
  1661. function ObjectCollisionMatrix() {
  1662. /**
  1663. * The matrix storage
  1664. * @property matrix
  1665. * @type {Object}
  1666. */
  1667. this.matrix = {};
  1668. }
  1669. /**
  1670. * @method get
  1671. * @param {Number} i
  1672. * @param {Number} j
  1673. * @return {Number}
  1674. */
  1675. ObjectCollisionMatrix.prototype.get = function(i, j) {
  1676. i = i.id;
  1677. j = j.id;
  1678. if (j > i) {
  1679. var temp = j;
  1680. j = i;
  1681. i = temp;
  1682. }
  1683. return i+'-'+j in this.matrix;
  1684. };
  1685. /**
  1686. * @method set
  1687. * @param {Number} i
  1688. * @param {Number} j
  1689. * @param {Number} value
  1690. */
  1691. ObjectCollisionMatrix.prototype.set = function(i, j, value) {
  1692. i = i.id;
  1693. j = j.id;
  1694. if (j > i) {
  1695. var temp = j;
  1696. j = i;
  1697. i = temp;
  1698. }
  1699. if (value) {
  1700. this.matrix[i+'-'+j] = true;
  1701. }
  1702. else {
  1703. delete this.matrix[i+'-'+j];
  1704. }
  1705. };
  1706. /**
  1707. * Empty the matrix
  1708. * @method reset
  1709. */
  1710. ObjectCollisionMatrix.prototype.reset = function() {
  1711. this.matrix = {};
  1712. };
  1713. /**
  1714. * Set max number of objects
  1715. * @method setNumObjects
  1716. * @param {Number} n
  1717. */
  1718. ObjectCollisionMatrix.prototype.setNumObjects = function(n) {
  1719. };
  1720. },{}],21:[function(require,module,exports){
  1721. module.exports = OverlapKeeper;
  1722. /**
  1723. * @class OverlapKeeper
  1724. * @constructor
  1725. */
  1726. function OverlapKeeper() {
  1727. this.current = [];
  1728. this.previous = [];
  1729. }
  1730. OverlapKeeper.prototype.getKey = function(i, j) {
  1731. if (j < i) {
  1732. var temp = j;
  1733. j = i;
  1734. i = temp;
  1735. }
  1736. return (i << 16) | j;
  1737. };
  1738. /**
  1739. * @method set
  1740. * @param {Number} i
  1741. * @param {Number} j
  1742. */
  1743. OverlapKeeper.prototype.set = function(i, j) {
  1744. // Insertion sort. This way the diff will have linear complexity.
  1745. var key = this.getKey(i, j);
  1746. var current = this.current;
  1747. var index = 0;
  1748. while(key > current[index]){
  1749. index++;
  1750. }
  1751. if(key === current[index]){
  1752. return; // Pair was already added
  1753. }
  1754. for(var j=current.length-1; j>=index; j--){
  1755. current[j + 1] = current[j];
  1756. }
  1757. current[index] = key;
  1758. };
  1759. /**
  1760. * @method tick
  1761. */
  1762. OverlapKeeper.prototype.tick = function() {
  1763. var tmp = this.current;
  1764. this.current = this.previous;
  1765. this.previous = tmp;
  1766. this.current.length = 0;
  1767. };
  1768. function unpackAndPush(array, key){
  1769. array.push((key & 0xFFFF0000) >> 16, key & 0x0000FFFF);
  1770. }
  1771. /**
  1772. * @method getDiff
  1773. * @param {array} additions
  1774. * @param {array} removals
  1775. */
  1776. OverlapKeeper.prototype.getDiff = function(additions, removals) {
  1777. var a = this.current;
  1778. var b = this.previous;
  1779. var al = a.length;
  1780. var bl = b.length;
  1781. var j=0;
  1782. for (var i = 0; i < al; i++) {
  1783. var found = false;
  1784. var keyA = a[i];
  1785. while(keyA > b[j]){
  1786. j++;
  1787. }
  1788. found = keyA === b[j];
  1789. if(!found){
  1790. unpackAndPush(additions, keyA);
  1791. }
  1792. }
  1793. j = 0;
  1794. for (var i = 0; i < bl; i++) {
  1795. var found = false;
  1796. var keyB = b[i];
  1797. while(keyB > a[j]){
  1798. j++;
  1799. }
  1800. found = a[j] === keyB;
  1801. if(!found){
  1802. unpackAndPush(removals, keyB);
  1803. }
  1804. }
  1805. };
  1806. },{}],22:[function(require,module,exports){
  1807. module.exports = Ray;
  1808. var Vec3 = require('../math/Vec3');
  1809. var Quaternion = require('../math/Quaternion');
  1810. var Transform = require('../math/Transform');
  1811. var ConvexPolyhedron = require('../shapes/ConvexPolyhedron');
  1812. var Box = require('../shapes/Box');
  1813. var RaycastResult = require('../collision/RaycastResult');
  1814. var Shape = require('../shapes/Shape');
  1815. var AABB = require('../collision/AABB');
  1816. /**
  1817. * A line in 3D space that intersects bodies and return points.
  1818. * @class Ray
  1819. * @constructor
  1820. * @param {Vec3} from
  1821. * @param {Vec3} to
  1822. */
  1823. function Ray(from, to){
  1824. /**
  1825. * @property {Vec3} from
  1826. */
  1827. this.from = from ? from.clone() : new Vec3();
  1828. /**
  1829. * @property {Vec3} to
  1830. */
  1831. this.to = to ? to.clone() : new Vec3();
  1832. /**
  1833. * @private
  1834. * @property {Vec3} _direction
  1835. */
  1836. this._direction = new Vec3();
  1837. /**
  1838. * The precision of the ray. Used when checking parallelity etc.
  1839. * @property {Number} precision
  1840. */
  1841. this.precision = 0.0001;
  1842. /**
  1843. * Set to true if you want the Ray to take .collisionResponse flags into account on bodies and shapes.
  1844. * @property {Boolean} checkCollisionResponse
  1845. */
  1846. this.checkCollisionResponse = true;
  1847. /**
  1848. * If set to true, the ray skips any hits with normal.dot(rayDirection) < 0.
  1849. * @property {Boolean} skipBackfaces
  1850. */
  1851. this.skipBackfaces = false;
  1852. /**
  1853. * @property {number} collisionFilterMask
  1854. * @default -1
  1855. */
  1856. this.collisionFilterMask = -1;
  1857. /**
  1858. * @property {number} collisionFilterGroup
  1859. * @default -1
  1860. */
  1861. this.collisionFilterGroup = -1;
  1862. /**
  1863. * The intersection mode. Should be Ray.ANY, Ray.ALL or Ray.CLOSEST.
  1864. * @property {number} mode
  1865. */
  1866. this.mode = Ray.ANY;
  1867. /**
  1868. * Current result object.
  1869. * @property {RaycastResult} result
  1870. */
  1871. this.result = new RaycastResult();
  1872. /**
  1873. * Will be set to true during intersectWorld() if the ray hit anything.
  1874. * @property {Boolean} hasHit
  1875. */
  1876. this.hasHit = false;
  1877. /**
  1878. * Current, user-provided result callback. Will be used if mode is Ray.ALL.
  1879. * @property {Function} callback
  1880. */
  1881. this.callback = function(result){};
  1882. }
  1883. Ray.prototype.constructor = Ray;
  1884. Ray.CLOSEST = 1;
  1885. Ray.ANY = 2;
  1886. Ray.ALL = 4;
  1887. var tmpAABB = new AABB();
  1888. var tmpArray = [];
  1889. /**
  1890. * Do itersection against all bodies in the given World.
  1891. * @method intersectWorld
  1892. * @param {World} world
  1893. * @param {object} options
  1894. * @return {Boolean} True if the ray hit anything, otherwise false.
  1895. */
  1896. Ray.prototype.intersectWorld = function (world, options) {
  1897. this.mode = options.mode || Ray.ANY;
  1898. this.result = options.result || new RaycastResult();
  1899. this.skipBackfaces = !!options.skipBackfaces;
  1900. this.collisionFilterMask = typeof(options.collisionFilterMask) !== 'undefined' ? options.collisionFilterMask : -1;
  1901. this.collisionFilterGroup = typeof(options.collisionFilterGroup) !== 'undefined' ? options.collisionFilterGroup : -1;
  1902. if(options.from){
  1903. this.from.copy(options.from);
  1904. }
  1905. if(options.to){
  1906. this.to.copy(options.to);
  1907. }
  1908. this.callback = options.callback || function(){};
  1909. this.hasHit = false;
  1910. this.result.reset();
  1911. this._updateDirection();
  1912. this.getAABB(tmpAABB);
  1913. tmpArray.length = 0;
  1914. world.broadphase.aabbQuery(world, tmpAABB, tmpArray);
  1915. this.intersectBodies(tmpArray);
  1916. return this.hasHit;
  1917. };
  1918. var v1 = new Vec3(),
  1919. v2 = new Vec3();
  1920. /*
  1921. * As per "Barycentric Technique" as named here http://www.blackpawn.com/texts/pointinpoly/default.html But without the division
  1922. */
  1923. Ray.pointInTriangle = pointInTriangle;
  1924. function pointInTriangle(p, a, b, c) {
  1925. c.vsub(a,v0);
  1926. b.vsub(a,v1);
  1927. p.vsub(a,v2);
  1928. var dot00 = v0.dot( v0 );
  1929. var dot01 = v0.dot( v1 );
  1930. var dot02 = v0.dot( v2 );
  1931. var dot11 = v1.dot( v1 );
  1932. var dot12 = v1.dot( v2 );
  1933. var u,v;
  1934. return ( (u = dot11 * dot02 - dot01 * dot12) >= 0 ) &&
  1935. ( (v = dot00 * dot12 - dot01 * dot02) >= 0 ) &&
  1936. ( u + v < ( dot00 * dot11 - dot01 * dot01 ) );
  1937. }
  1938. /**
  1939. * Shoot a ray at a body, get back information about the hit.
  1940. * @method intersectBody
  1941. * @private
  1942. * @param {Body} body
  1943. * @param {RaycastResult} [result] Deprecated - set the result property of the Ray instead.
  1944. */
  1945. var intersectBody_xi = new Vec3();
  1946. var intersectBody_qi = new Quaternion();
  1947. Ray.prototype.intersectBody = function (body, result) {
  1948. if(result){
  1949. this.result = result;
  1950. this._updateDirection();
  1951. }
  1952. var checkCollisionResponse = this.checkCollisionResponse;
  1953. if(checkCollisionResponse && !body.collisionResponse){
  1954. return;
  1955. }
  1956. if((this.collisionFilterGroup & body.collisionFilterMask)===0 || (body.collisionFilterGroup & this.collisionFilterMask)===0){
  1957. return;
  1958. }
  1959. var xi = intersectBody_xi;
  1960. var qi = intersectBody_qi;
  1961. for (var i = 0, N = body.shapes.length; i < N; i++) {
  1962. var shape = body.shapes[i];
  1963. if(checkCollisionResponse && !shape.collisionResponse){
  1964. continue; // Skip
  1965. }
  1966. body.quaternion.mult(body.shapeOrientations[i], qi);
  1967. body.quaternion.vmult(body.shapeOffsets[i], xi);
  1968. xi.vadd(body.position, xi);
  1969. this.intersectShape(
  1970. shape,
  1971. qi,
  1972. xi,
  1973. body
  1974. );
  1975. if(this.result._shouldStop){
  1976. break;
  1977. }
  1978. }
  1979. };
  1980. /**
  1981. * @method intersectBodies
  1982. * @param {Array} bodies An array of Body objects.
  1983. * @param {RaycastResult} [result] Deprecated
  1984. */
  1985. Ray.prototype.intersectBodies = function (bodies, result) {
  1986. if(result){
  1987. this.result = result;
  1988. this._updateDirection();
  1989. }
  1990. for ( var i = 0, l = bodies.length; !this.result._shouldStop && i < l; i ++ ) {
  1991. this.intersectBody(bodies[i]);
  1992. }
  1993. };
  1994. /**
  1995. * Updates the _direction vector.
  1996. * @private
  1997. * @method _updateDirection
  1998. */
  1999. Ray.prototype._updateDirection = function(){
  2000. this.to.vsub(this.from, this._direction);
  2001. this._direction.normalize();
  2002. };
  2003. /**
  2004. * @method intersectShape
  2005. * @private
  2006. * @param {Shape} shape
  2007. * @param {Quaternion} quat
  2008. * @param {Vec3} position
  2009. * @param {Body} body
  2010. */
  2011. Ray.prototype.intersectShape = function(shape, quat, position, body){
  2012. var from = this.from;
  2013. // Checking boundingSphere
  2014. var distance = distanceFromIntersection(from, this._direction, position);
  2015. if ( distance > shape.boundingSphereRadius ) {
  2016. return;
  2017. }
  2018. var intersectMethod = this[shape.type];
  2019. if(intersectMethod){
  2020. intersectMethod.call(this, shape, quat, position, body, shape);
  2021. }
  2022. };
  2023. var vector = new Vec3();
  2024. var normal = new Vec3();
  2025. var intersectPoint = new Vec3();
  2026. var a = new Vec3();
  2027. var b = new Vec3();
  2028. var c = new Vec3();
  2029. var d = new Vec3();
  2030. var tmpRaycastResult = new RaycastResult();
  2031. /**
  2032. * @method intersectBox
  2033. * @private
  2034. * @param {Shape} shape
  2035. * @param {Quaternion} quat
  2036. * @param {Vec3} position
  2037. * @param {Body} body
  2038. */
  2039. Ray.prototype.intersectBox = function(shape, quat, position, body, reportedShape){
  2040. return this.intersectConvex(shape.convexPolyhedronRepresentation, quat, position, body, reportedShape);
  2041. };
  2042. Ray.prototype[Shape.types.BOX] = Ray.prototype.intersectBox;
  2043. /**
  2044. * @method intersectPlane
  2045. * @private
  2046. * @param {Shape} shape
  2047. * @param {Quaternion} quat
  2048. * @param {Vec3} position
  2049. * @param {Body} body
  2050. */
  2051. Ray.prototype.intersectPlane = function(shape, quat, position, body, reportedShape){
  2052. var from = this.from;
  2053. var to = this.to;
  2054. var direction = this._direction;
  2055. // Get plane normal
  2056. var worldNormal = new Vec3(0, 0, 1);
  2057. quat.vmult(worldNormal, worldNormal);
  2058. var len = new Vec3();
  2059. from.vsub(position, len);
  2060. var planeToFrom = len.dot(worldNormal);
  2061. to.vsub(position, len);
  2062. var planeToTo = len.dot(worldNormal);
  2063. if(planeToFrom * planeToTo > 0){
  2064. // "from" and "to" are on the same side of the plane... bail out
  2065. return;
  2066. }
  2067. if(from.distanceTo(to) < planeToFrom){
  2068. return;
  2069. }
  2070. var n_dot_dir = worldNormal.dot(direction);
  2071. if (Math.abs(n_dot_dir) < this.precision) {
  2072. // No intersection
  2073. return;
  2074. }
  2075. var planePointToFrom = new Vec3();
  2076. var dir_scaled_with_t = new Vec3();
  2077. var hitPointWorld = new Vec3();
  2078. from.vsub(position, planePointToFrom);
  2079. var t = -worldNormal.dot(planePointToFrom) / n_dot_dir;
  2080. direction.scale(t, dir_scaled_with_t);
  2081. from.vadd(dir_scaled_with_t, hitPointWorld);
  2082. this.reportIntersection(worldNormal, hitPointWorld, reportedShape, body, -1);
  2083. };
  2084. Ray.prototype[Shape.types.PLANE] = Ray.prototype.intersectPlane;
  2085. /**
  2086. * Get the world AABB of the ray.
  2087. * @method getAABB
  2088. * @param {AABB} aabb
  2089. */
  2090. Ray.prototype.getAABB = function(result){
  2091. var to = this.to;
  2092. var from = this.from;
  2093. result.lowerBound.x = Math.min(to.x, from.x);
  2094. result.lowerBound.y = Math.min(to.y, from.y);
  2095. result.lowerBound.z = Math.min(to.z, from.z);
  2096. result.upperBound.x = Math.max(to.x, from.x);
  2097. result.upperBound.y = Math.max(to.y, from.y);
  2098. result.upperBound.z = Math.max(to.z, from.z);
  2099. };
  2100. var intersectConvexOptions = {
  2101. faceList: [0]
  2102. };
  2103. var worldPillarOffset = new Vec3();
  2104. var intersectHeightfield_localRay = new Ray();
  2105. var intersectHeightfield_index = [];
  2106. var intersectHeightfield_minMax = [];
  2107. /**
  2108. * @method intersectHeightfield
  2109. * @private
  2110. * @param {Shape} shape
  2111. * @param {Quaternion} quat
  2112. * @param {Vec3} position
  2113. * @param {Body} body
  2114. */
  2115. Ray.prototype.intersectHeightfield = function(shape, quat, position, body, reportedShape){
  2116. var data = shape.data,
  2117. w = shape.elementSize;
  2118. // Convert the ray to local heightfield coordinates
  2119. var localRay = intersectHeightfield_localRay; //new Ray(this.from, this.to);
  2120. localRay.from.copy(this.from);
  2121. localRay.to.copy(this.to);
  2122. Transform.pointToLocalFrame(position, quat, localRay.from, localRay.from);
  2123. Transform.pointToLocalFrame(position, quat, localRay.to, localRay.to);
  2124. localRay._updateDirection();
  2125. // Get the index of the data points to test against
  2126. var index = intersectHeightfield_index;
  2127. var iMinX, iMinY, iMaxX, iMaxY;
  2128. // Set to max
  2129. iMinX = iMinY = 0;
  2130. iMaxX = iMaxY = shape.data.length - 1;
  2131. var aabb = new AABB();
  2132. localRay.getAABB(aabb);
  2133. shape.getIndexOfPosition(aabb.lowerBound.x, aabb.lowerBound.y, index, true);
  2134. iMinX = Math.max(iMinX, index[0]);
  2135. iMinY = Math.max(iMinY, index[1]);
  2136. shape.getIndexOfPosition(aabb.upperBound.x, aabb.upperBound.y, index, true);
  2137. iMaxX = Math.min(iMaxX, index[0] + 1);
  2138. iMaxY = Math.min(iMaxY, index[1] + 1);
  2139. for(var i = iMinX; i < iMaxX; i++){
  2140. for(var j = iMinY; j < iMaxY; j++){
  2141. if(this.result._shouldStop){
  2142. return;
  2143. }
  2144. shape.getAabbAtIndex(i, j, aabb);
  2145. if(!aabb.overlapsRay(localRay)){
  2146. continue;
  2147. }
  2148. // Lower triangle
  2149. shape.getConvexTrianglePillar(i, j, false);
  2150. Transform.pointToWorldFrame(position, quat, shape.pillarOffset, worldPillarOffset);
  2151. this.intersectConvex(shape.pillarConvex, quat, worldPillarOffset, body, reportedShape, intersectConvexOptions);
  2152. if(this.result._shouldStop){
  2153. return;
  2154. }
  2155. // Upper triangle
  2156. shape.getConvexTrianglePillar(i, j, true);
  2157. Transform.pointToWorldFrame(position, quat, shape.pillarOffset, worldPillarOffset);
  2158. this.intersectConvex(shape.pillarConvex, quat, worldPillarOffset, body, reportedShape, intersectConvexOptions);
  2159. }
  2160. }
  2161. };
  2162. Ray.prototype[Shape.types.HEIGHTFIELD] = Ray.prototype.intersectHeightfield;
  2163. var Ray_intersectSphere_intersectionPoint = new Vec3();
  2164. var Ray_intersectSphere_normal = new Vec3();
  2165. /**
  2166. * @method intersectSphere
  2167. * @private
  2168. * @param {Shape} shape
  2169. * @param {Quaternion} quat
  2170. * @param {Vec3} position
  2171. * @param {Body} body
  2172. */
  2173. Ray.prototype.intersectSphere = function(shape, quat, position, body, reportedShape){
  2174. var from = this.from,
  2175. to = this.to,
  2176. r = shape.radius;
  2177. var a = Math.pow(to.x - from.x, 2) + Math.pow(to.y - from.y, 2) + Math.pow(to.z - from.z, 2);
  2178. 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));
  2179. 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);
  2180. var delta = Math.pow(b, 2) - 4 * a * c;
  2181. var intersectionPoint = Ray_intersectSphere_intersectionPoint;
  2182. var normal = Ray_intersectSphere_normal;
  2183. if(delta < 0){
  2184. // No intersection
  2185. return;
  2186. } else if(delta === 0){
  2187. // single intersection point
  2188. from.lerp(to, delta, intersectionPoint);
  2189. intersectionPoint.vsub(position, normal);
  2190. normal.normalize();
  2191. this.reportIntersection(normal, intersectionPoint, reportedShape, body, -1);
  2192. } else {
  2193. var d1 = (- b - Math.sqrt(delta)) / (2 * a);
  2194. var d2 = (- b + Math.sqrt(delta)) / (2 * a);
  2195. if(d1 >= 0 && d1 <= 1){
  2196. from.lerp(to, d1, intersectionPoint);
  2197. intersectionPoint.vsub(position, normal);
  2198. normal.normalize();
  2199. this.reportIntersection(normal, intersectionPoint, reportedShape, body, -1);
  2200. }
  2201. if(this.result._shouldStop){
  2202. return;
  2203. }
  2204. if(d2 >= 0 && d2 <= 1){
  2205. from.lerp(to, d2, intersectionPoint);
  2206. intersectionPoint.vsub(position, normal);
  2207. normal.normalize();
  2208. this.reportIntersection(normal, intersectionPoint, reportedShape, body, -1);
  2209. }
  2210. }
  2211. };
  2212. Ray.prototype[Shape.types.SPHERE] = Ray.prototype.intersectSphere;
  2213. var intersectConvex_normal = new Vec3();
  2214. var intersectConvex_minDistNormal = new Vec3();
  2215. var intersectConvex_minDistIntersect = new Vec3();
  2216. var intersectConvex_vector = new Vec3();
  2217. /**
  2218. * @method intersectConvex
  2219. * @private
  2220. * @param {Shape} shape
  2221. * @param {Quaternion} quat
  2222. * @param {Vec3} position
  2223. * @param {Body} body
  2224. * @param {object} [options]
  2225. * @param {array} [options.faceList]
  2226. */
  2227. Ray.prototype.intersectConvex = function intersectConvex(
  2228. shape,
  2229. quat,
  2230. position,
  2231. body,
  2232. reportedShape,
  2233. options
  2234. ){
  2235. var minDistNormal = intersectConvex_minDistNormal;
  2236. var normal = intersectConvex_normal;
  2237. var vector = intersectConvex_vector;
  2238. var minDistIntersect = intersectConvex_minDistIntersect;
  2239. var faceList = (options && options.faceList) || null;
  2240. // Checking faces
  2241. var faces = shape.faces,
  2242. vertices = shape.vertices,
  2243. normals = shape.faceNormals;
  2244. var direction = this._direction;
  2245. var from = this.from;
  2246. var to = this.to;
  2247. var fromToDistance = from.distanceTo(to);
  2248. var minDist = -1;
  2249. var Nfaces = faceList ? faceList.length : faces.length;
  2250. var result = this.result;
  2251. for (var j = 0; !result._shouldStop && j < Nfaces; j++) {
  2252. var fi = faceList ? faceList[j] : j;
  2253. var face = faces[fi];
  2254. var faceNormal = normals[fi];
  2255. var q = quat;
  2256. var x = position;
  2257. // determine if ray intersects the plane of the face
  2258. // note: this works regardless of the direction of the face normal
  2259. // Get plane point in world coordinates...
  2260. vector.copy(vertices[face[0]]);
  2261. q.vmult(vector,vector);
  2262. vector.vadd(x,vector);
  2263. // ...but make it relative to the ray from. We'll fix this later.
  2264. vector.vsub(from,vector);
  2265. // Get plane normal
  2266. q.vmult(faceNormal,normal);
  2267. // If this dot product is negative, we have something interesting
  2268. var dot = direction.dot(normal);
  2269. // Bail out if ray and plane are parallel
  2270. if ( Math.abs( dot ) < this.precision ){
  2271. continue;
  2272. }
  2273. // calc distance to plane
  2274. var scalar = normal.dot(vector) / dot;
  2275. // if negative distance, then plane is behind ray
  2276. if (scalar < 0){
  2277. continue;
  2278. }
  2279. // if (dot < 0) {
  2280. // Intersection point is from + direction * scalar
  2281. direction.mult(scalar,intersectPoint);
  2282. intersectPoint.vadd(from,intersectPoint);
  2283. // a is the point we compare points b and c with.
  2284. a.copy(vertices[face[0]]);
  2285. q.vmult(a,a);
  2286. x.vadd(a,a);
  2287. for(var i = 1; !result._shouldStop && i < face.length - 1; i++){
  2288. // Transform 3 vertices to world coords
  2289. b.copy(vertices[face[i]]);
  2290. c.copy(vertices[face[i+1]]);
  2291. q.vmult(b,b);
  2292. q.vmult(c,c);
  2293. x.vadd(b,b);
  2294. x.vadd(c,c);
  2295. var distance = intersectPoint.distanceTo(from);
  2296. if(!(pointInTriangle(intersectPoint, a, b, c) || pointInTriangle(intersectPoint, b, a, c)) || distance > fromToDistance){
  2297. continue;
  2298. }
  2299. this.reportIntersection(normal, intersectPoint, reportedShape, body, fi);
  2300. }
  2301. // }
  2302. }
  2303. };
  2304. Ray.prototype[Shape.types.CONVEXPOLYHEDRON] = Ray.prototype.intersectConvex;
  2305. var intersectTrimesh_normal = new Vec3();
  2306. var intersectTrimesh_localDirection = new Vec3();
  2307. var intersectTrimesh_localFrom = new Vec3();
  2308. var intersectTrimesh_localTo = new Vec3();
  2309. var intersectTrimesh_worldNormal = new Vec3();
  2310. var intersectTrimesh_worldIntersectPoint = new Vec3();
  2311. var intersectTrimesh_localAABB = new AABB();
  2312. var intersectTrimesh_triangles = [];
  2313. var intersectTrimesh_treeTransform = new Transform();
  2314. /**
  2315. * @method intersectTrimesh
  2316. * @private
  2317. * @param {Shape} shape
  2318. * @param {Quaternion} quat
  2319. * @param {Vec3} position
  2320. * @param {Body} body
  2321. * @param {object} [options]
  2322. * @todo Optimize by transforming the world to local space first.
  2323. * @todo Use Octree lookup
  2324. */
  2325. Ray.prototype.intersectTrimesh = function intersectTrimesh(
  2326. mesh,
  2327. quat,
  2328. position,
  2329. body,
  2330. reportedShape,
  2331. options
  2332. ){
  2333. var normal = intersectTrimesh_normal;
  2334. var triangles = intersectTrimesh_triangles;
  2335. var treeTransform = intersectTrimesh_treeTransform;
  2336. var minDistNormal = intersectConvex_minDistNormal;
  2337. var vector = intersectConvex_vector;
  2338. var minDistIntersect = intersectConvex_minDistIntersect;
  2339. var localAABB = intersectTrimesh_localAABB;
  2340. var localDirection = intersectTrimesh_localDirection;
  2341. var localFrom = intersectTrimesh_localFrom;
  2342. var localTo = intersectTrimesh_localTo;
  2343. var worldIntersectPoint = intersectTrimesh_worldIntersectPoint;
  2344. var worldNormal = intersectTrimesh_worldNormal;
  2345. var faceList = (options && options.faceList) || null;
  2346. // Checking faces
  2347. var indices = mesh.indices,
  2348. vertices = mesh.vertices,
  2349. normals = mesh.faceNormals;
  2350. var from = this.from;
  2351. var to = this.to;
  2352. var direction = this._direction;
  2353. var minDist = -1;
  2354. treeTransform.position.copy(position);
  2355. treeTransform.quaternion.copy(quat);
  2356. // Transform ray to local space!
  2357. Transform.vectorToLocalFrame(position, quat, direction, localDirection);
  2358. Transform.pointToLocalFrame(position, quat, from, localFrom);
  2359. Transform.pointToLocalFrame(position, quat, to, localTo);
  2360. localTo.x *= mesh.scale.x;
  2361. localTo.y *= mesh.scale.y;
  2362. localTo.z *= mesh.scale.z;
  2363. localFrom.x *= mesh.scale.x;
  2364. localFrom.y *= mesh.scale.y;
  2365. localFrom.z *= mesh.scale.z;
  2366. localTo.vsub(localFrom, localDirection);
  2367. localDirection.normalize();
  2368. var fromToDistanceSquared = localFrom.distanceSquared(localTo);
  2369. mesh.tree.rayQuery(this, treeTransform, triangles);
  2370. for (var i = 0, N = triangles.length; !this.result._shouldStop && i !== N; i++) {
  2371. var trianglesIndex = triangles[i];
  2372. mesh.getNormal(trianglesIndex, normal);
  2373. // determine if ray intersects the plane of the face
  2374. // note: this works regardless of the direction of the face normal
  2375. // Get plane point in world coordinates...
  2376. mesh.getVertex(indices[trianglesIndex * 3], a);
  2377. // ...but make it relative to the ray from. We'll fix this later.
  2378. a.vsub(localFrom,vector);
  2379. // If this dot product is negative, we have something interesting
  2380. var dot = localDirection.dot(normal);
  2381. // Bail out if ray and plane are parallel
  2382. // if (Math.abs( dot ) < this.precision){
  2383. // continue;
  2384. // }
  2385. // calc distance to plane
  2386. var scalar = normal.dot(vector) / dot;
  2387. // if negative distance, then plane is behind ray
  2388. if (scalar < 0){
  2389. continue;
  2390. }
  2391. // Intersection point is from + direction * scalar
  2392. localDirection.scale(scalar,intersectPoint);
  2393. intersectPoint.vadd(localFrom,intersectPoint);
  2394. // Get triangle vertices
  2395. mesh.getVertex(indices[trianglesIndex * 3 + 1], b);
  2396. mesh.getVertex(indices[trianglesIndex * 3 + 2], c);
  2397. var squaredDistance = intersectPoint.distanceSquared(localFrom);
  2398. if(!(pointInTriangle(intersectPoint, b, a, c) || pointInTriangle(intersectPoint, a, b, c)) || squaredDistance > fromToDistanceSquared){
  2399. continue;
  2400. }
  2401. // transform intersectpoint and normal to world
  2402. Transform.vectorToWorldFrame(quat, normal, worldNormal);
  2403. Transform.pointToWorldFrame(position, quat, intersectPoint, worldIntersectPoint);
  2404. this.reportIntersection(worldNormal, worldIntersectPoint, reportedShape, body, trianglesIndex);
  2405. }
  2406. triangles.length = 0;
  2407. };
  2408. Ray.prototype[Shape.types.TRIMESH] = Ray.prototype.intersectTrimesh;
  2409. /**
  2410. * @method reportIntersection
  2411. * @private
  2412. * @param {Vec3} normal
  2413. * @param {Vec3} hitPointWorld
  2414. * @param {Shape} shape
  2415. * @param {Body} body
  2416. * @return {boolean} True if the intersections should continue
  2417. */
  2418. Ray.prototype.reportIntersection = function(normal, hitPointWorld, shape, body, hitFaceIndex){
  2419. var from = this.from;
  2420. var to = this.to;
  2421. var distance = from.distanceTo(hitPointWorld);
  2422. var result = this.result;
  2423. // Skip back faces?
  2424. if(this.skipBackfaces && normal.dot(this._direction) > 0){
  2425. return;
  2426. }
  2427. result.hitFaceIndex = typeof(hitFaceIndex) !== 'undefined' ? hitFaceIndex : -1;
  2428. switch(this.mode){
  2429. case Ray.ALL:
  2430. this.hasHit = true;
  2431. result.set(
  2432. from,
  2433. to,
  2434. normal,
  2435. hitPointWorld,
  2436. shape,
  2437. body,
  2438. distance
  2439. );
  2440. result.hasHit = true;
  2441. this.callback(result);
  2442. break;
  2443. case Ray.CLOSEST:
  2444. // Store if closer than current closest
  2445. if(distance < result.distance || !result.hasHit){
  2446. this.hasHit = true;
  2447. result.hasHit = true;
  2448. result.set(
  2449. from,
  2450. to,
  2451. normal,
  2452. hitPointWorld,
  2453. shape,
  2454. body,
  2455. distance
  2456. );
  2457. }
  2458. break;
  2459. case Ray.ANY:
  2460. // Report and stop.
  2461. this.hasHit = true;
  2462. result.hasHit = true;
  2463. result.set(
  2464. from,
  2465. to,
  2466. normal,
  2467. hitPointWorld,
  2468. shape,
  2469. body,
  2470. distance
  2471. );
  2472. result._shouldStop = true;
  2473. break;
  2474. }
  2475. };
  2476. var v0 = new Vec3(),
  2477. intersect = new Vec3();
  2478. function distanceFromIntersection(from, direction, position) {
  2479. // v0 is vector from from to position
  2480. position.vsub(from,v0);
  2481. var dot = v0.dot(direction);
  2482. // intersect = direction*dot + from
  2483. direction.mult(dot,intersect);
  2484. intersect.vadd(from,intersect);
  2485. var distance = position.distanceTo(intersect);
  2486. return distance;
  2487. }
  2488. },{"../collision/AABB":15,"../collision/RaycastResult":23,"../math/Quaternion":41,"../math/Transform":42,"../math/Vec3":43,"../shapes/Box":50,"../shapes/ConvexPolyhedron":51,"../shapes/Shape":56}],23:[function(require,module,exports){
  2489. var Vec3 = require('../math/Vec3');
  2490. module.exports = RaycastResult;
  2491. /**
  2492. * Storage for Ray casting data.
  2493. * @class RaycastResult
  2494. * @constructor
  2495. */
  2496. function RaycastResult(){
  2497. /**
  2498. * @property {Vec3} rayFromWorld
  2499. */
  2500. this.rayFromWorld = new Vec3();
  2501. /**
  2502. * @property {Vec3} rayToWorld
  2503. */
  2504. this.rayToWorld = new Vec3();
  2505. /**
  2506. * @property {Vec3} hitNormalWorld
  2507. */
  2508. this.hitNormalWorld = new Vec3();
  2509. /**
  2510. * @property {Vec3} hitPointWorld
  2511. */
  2512. this.hitPointWorld = new Vec3();
  2513. /**
  2514. * @property {boolean} hasHit
  2515. */
  2516. this.hasHit = false;
  2517. /**
  2518. * The hit shape, or null.
  2519. * @property {Shape} shape
  2520. */
  2521. this.shape = null;
  2522. /**
  2523. * The hit body, or null.
  2524. * @property {Body} body
  2525. */
  2526. this.body = null;
  2527. /**
  2528. * The index of the hit triangle, if the hit shape was a trimesh.
  2529. * @property {number} hitFaceIndex
  2530. * @default -1
  2531. */
  2532. this.hitFaceIndex = -1;
  2533. /**
  2534. * Distance to the hit. Will be set to -1 if there was no hit.
  2535. * @property {number} distance
  2536. * @default -1
  2537. */
  2538. this.distance = -1;
  2539. /**
  2540. * If the ray should stop traversing the bodies.
  2541. * @private
  2542. * @property {Boolean} _shouldStop
  2543. * @default false
  2544. */
  2545. this._shouldStop = false;
  2546. }
  2547. /**
  2548. * Reset all result data.
  2549. * @method reset
  2550. */
  2551. RaycastResult.prototype.reset = function () {
  2552. this.rayFromWorld.setZero();
  2553. this.rayToWorld.setZero();
  2554. this.hitNormalWorld.setZero();
  2555. this.hitPointWorld.setZero();
  2556. this.hasHit = false;
  2557. this.shape = null;
  2558. this.body = null;
  2559. this.hitFaceIndex = -1;
  2560. this.distance = -1;
  2561. this._shouldStop = false;
  2562. };
  2563. /**
  2564. * @method abort
  2565. */
  2566. RaycastResult.prototype.abort = function(){
  2567. this._shouldStop = true;
  2568. };
  2569. /**
  2570. * @method set
  2571. * @param {Vec3} rayFromWorld
  2572. * @param {Vec3} rayToWorld
  2573. * @param {Vec3} hitNormalWorld
  2574. * @param {Vec3} hitPointWorld
  2575. * @param {Shape} shape
  2576. * @param {Body} body
  2577. * @param {number} distance
  2578. */
  2579. RaycastResult.prototype.set = function(
  2580. rayFromWorld,
  2581. rayToWorld,
  2582. hitNormalWorld,
  2583. hitPointWorld,
  2584. shape,
  2585. body,
  2586. distance
  2587. ){
  2588. this.rayFromWorld.copy(rayFromWorld);
  2589. this.rayToWorld.copy(rayToWorld);
  2590. this.hitNormalWorld.copy(hitNormalWorld);
  2591. this.hitPointWorld.copy(hitPointWorld);
  2592. this.shape = shape;
  2593. this.body = body;
  2594. this.distance = distance;
  2595. };
  2596. },{"../math/Vec3":43}],24:[function(require,module,exports){
  2597. var Shape = require('../shapes/Shape');
  2598. var Broadphase = require('../collision/Broadphase');
  2599. module.exports = SAPBroadphase;
  2600. /**
  2601. * Sweep and prune broadphase along one axis.
  2602. *
  2603. * @class SAPBroadphase
  2604. * @constructor
  2605. * @param {World} [world]
  2606. * @extends Broadphase
  2607. */
  2608. function SAPBroadphase(world){
  2609. Broadphase.apply(this);
  2610. /**
  2611. * List of bodies currently in the broadphase.
  2612. * @property axisList
  2613. * @type {Array}
  2614. */
  2615. this.axisList = [];
  2616. /**
  2617. * The world to search in.
  2618. * @property world
  2619. * @type {World}
  2620. */
  2621. this.world = null;
  2622. /**
  2623. * 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.
  2624. * @property axisIndex
  2625. * @type {Number}
  2626. */
  2627. this.axisIndex = 0;
  2628. var axisList = this.axisList;
  2629. this._addBodyHandler = function(e){
  2630. axisList.push(e.body);
  2631. };
  2632. this._removeBodyHandler = function(e){
  2633. var idx = axisList.indexOf(e.body);
  2634. if(idx !== -1){
  2635. axisList.splice(idx,1);
  2636. }
  2637. };
  2638. if(world){
  2639. this.setWorld(world);
  2640. }
  2641. }
  2642. SAPBroadphase.prototype = new Broadphase();
  2643. /**
  2644. * Change the world
  2645. * @method setWorld
  2646. * @param {World} world
  2647. */
  2648. SAPBroadphase.prototype.setWorld = function(world){
  2649. // Clear the old axis array
  2650. this.axisList.length = 0;
  2651. // Add all bodies from the new world
  2652. for(var i=0; i<world.bodies.length; i++){
  2653. this.axisList.push(world.bodies[i]);
  2654. }
  2655. // Remove old handlers, if any
  2656. world.removeEventListener("addBody", this._addBodyHandler);
  2657. world.removeEventListener("removeBody", this._removeBodyHandler);
  2658. // Add handlers to update the list of bodies.
  2659. world.addEventListener("addBody", this._addBodyHandler);
  2660. world.addEventListener("removeBody", this._removeBodyHandler);
  2661. this.world = world;
  2662. this.dirty = true;
  2663. };
  2664. /**
  2665. * @static
  2666. * @method insertionSortX
  2667. * @param {Array} a
  2668. * @return {Array}
  2669. */
  2670. SAPBroadphase.insertionSortX = function(a) {
  2671. for(var i=1,l=a.length;i<l;i++) {
  2672. var v = a[i];
  2673. for(var j=i - 1;j>=0;j--) {
  2674. if(a[j].aabb.lowerBound.x <= v.aabb.lowerBound.x){
  2675. break;
  2676. }
  2677. a[j+1] = a[j];
  2678. }
  2679. a[j+1] = v;
  2680. }
  2681. return a;
  2682. };
  2683. /**
  2684. * @static
  2685. * @method insertionSortY
  2686. * @param {Array} a
  2687. * @return {Array}
  2688. */
  2689. SAPBroadphase.insertionSortY = function(a) {
  2690. for(var i=1,l=a.length;i<l;i++) {
  2691. var v = a[i];
  2692. for(var j=i - 1;j>=0;j--) {
  2693. if(a[j].aabb.lowerBound.y <= v.aabb.lowerBound.y){
  2694. break;
  2695. }
  2696. a[j+1] = a[j];
  2697. }
  2698. a[j+1] = v;
  2699. }
  2700. return a;
  2701. };
  2702. /**
  2703. * @static
  2704. * @method insertionSortZ
  2705. * @param {Array} a
  2706. * @return {Array}
  2707. */
  2708. SAPBroadphase.insertionSortZ = function(a) {
  2709. for(var i=1,l=a.length;i<l;i++) {
  2710. var v = a[i];
  2711. for(var j=i - 1;j>=0;j--) {
  2712. if(a[j].aabb.lowerBound.z <= v.aabb.lowerBound.z){
  2713. break;
  2714. }
  2715. a[j+1] = a[j];
  2716. }
  2717. a[j+1] = v;
  2718. }
  2719. return a;
  2720. };
  2721. /**
  2722. * Collect all collision pairs
  2723. * @method collisionPairs
  2724. * @param {World} world
  2725. * @param {Array} p1
  2726. * @param {Array} p2
  2727. */
  2728. SAPBroadphase.prototype.collisionPairs = function(world,p1,p2){
  2729. var bodies = this.axisList,
  2730. N = bodies.length,
  2731. axisIndex = this.axisIndex,
  2732. i, j;
  2733. if(this.dirty){
  2734. this.sortList();
  2735. this.dirty = false;
  2736. }
  2737. // Look through the list
  2738. for(i=0; i !== N; i++){
  2739. var bi = bodies[i];
  2740. for(j=i+1; j < N; j++){
  2741. var bj = bodies[j];
  2742. if(!this.needBroadphaseCollision(bi,bj)){
  2743. continue;
  2744. }
  2745. if(!SAPBroadphase.checkBounds(bi,bj,axisIndex)){
  2746. break;
  2747. }
  2748. this.intersectionTest(bi,bj,p1,p2);
  2749. }
  2750. }
  2751. };
  2752. SAPBroadphase.prototype.sortList = function(){
  2753. var axisList = this.axisList;
  2754. var axisIndex = this.axisIndex;
  2755. var N = axisList.length;
  2756. // Update AABBs
  2757. for(var i = 0; i!==N; i++){
  2758. var bi = axisList[i];
  2759. if(bi.aabbNeedsUpdate){
  2760. bi.computeAABB();
  2761. }
  2762. }
  2763. // Sort the list
  2764. if(axisIndex === 0){
  2765. SAPBroadphase.insertionSortX(axisList);
  2766. } else if(axisIndex === 1){
  2767. SAPBroadphase.insertionSortY(axisList);
  2768. } else if(axisIndex === 2){
  2769. SAPBroadphase.insertionSortZ(axisList);
  2770. }
  2771. };
  2772. /**
  2773. * Check if the bounds of two bodies overlap, along the given SAP axis.
  2774. * @static
  2775. * @method checkBounds
  2776. * @param {Body} bi
  2777. * @param {Body} bj
  2778. * @param {Number} axisIndex
  2779. * @return {Boolean}
  2780. */
  2781. SAPBroadphase.checkBounds = function(bi, bj, axisIndex){
  2782. var biPos;
  2783. var bjPos;
  2784. if(axisIndex === 0){
  2785. biPos = bi.position.x;
  2786. bjPos = bj.position.x;
  2787. } else if(axisIndex === 1){
  2788. biPos = bi.position.y;
  2789. bjPos = bj.position.y;
  2790. } else if(axisIndex === 2){
  2791. biPos = bi.position.z;
  2792. bjPos = bj.position.z;
  2793. }
  2794. var ri = bi.boundingRadius,
  2795. rj = bj.boundingRadius,
  2796. boundA1 = biPos - ri,
  2797. boundA2 = biPos + ri,
  2798. boundB1 = bjPos - rj,
  2799. boundB2 = bjPos + rj;
  2800. return boundB1 < boundA2;
  2801. };
  2802. /**
  2803. * Computes the variance of the body positions and estimates the best
  2804. * axis to use. Will automatically set property .axisIndex.
  2805. * @method autoDetectAxis
  2806. */
  2807. SAPBroadphase.prototype.autoDetectAxis = function(){
  2808. var sumX=0,
  2809. sumX2=0,
  2810. sumY=0,
  2811. sumY2=0,
  2812. sumZ=0,
  2813. sumZ2=0,
  2814. bodies = this.axisList,
  2815. N = bodies.length,
  2816. invN=1/N;
  2817. for(var i=0; i!==N; i++){
  2818. var b = bodies[i];
  2819. var centerX = b.position.x;
  2820. sumX += centerX;
  2821. sumX2 += centerX*centerX;
  2822. var centerY = b.position.y;
  2823. sumY += centerY;
  2824. sumY2 += centerY*centerY;
  2825. var centerZ = b.position.z;
  2826. sumZ += centerZ;
  2827. sumZ2 += centerZ*centerZ;
  2828. }
  2829. var varianceX = sumX2 - sumX*sumX*invN,
  2830. varianceY = sumY2 - sumY*sumY*invN,
  2831. varianceZ = sumZ2 - sumZ*sumZ*invN;
  2832. if(varianceX > varianceY){
  2833. if(varianceX > varianceZ){
  2834. this.axisIndex = 0;
  2835. } else{
  2836. this.axisIndex = 2;
  2837. }
  2838. } else if(varianceY > varianceZ){
  2839. this.axisIndex = 1;
  2840. } else{
  2841. this.axisIndex = 2;
  2842. }
  2843. };
  2844. /**
  2845. * Returns all the bodies within an AABB.
  2846. * @method aabbQuery
  2847. * @param {World} world
  2848. * @param {AABB} aabb
  2849. * @param {array} result An array to store resulting bodies in.
  2850. * @return {array}
  2851. */
  2852. SAPBroadphase.prototype.aabbQuery = function(world, aabb, result){
  2853. result = result || [];
  2854. if(this.dirty){
  2855. this.sortList();
  2856. this.dirty = false;
  2857. }
  2858. var axisIndex = this.axisIndex, axis = 'x';
  2859. if(axisIndex === 1){ axis = 'y'; }
  2860. if(axisIndex === 2){ axis = 'z'; }
  2861. var axisList = this.axisList;
  2862. var lower = aabb.lowerBound[axis];
  2863. var upper = aabb.upperBound[axis];
  2864. for(var i = 0; i < axisList.length; i++){
  2865. var b = axisList[i];
  2866. if(b.aabbNeedsUpdate){
  2867. b.computeAABB();
  2868. }
  2869. if(b.aabb.overlaps(aabb)){
  2870. result.push(b);
  2871. }
  2872. }
  2873. return result;
  2874. };
  2875. },{"../collision/Broadphase":17,"../shapes/Shape":56}],25:[function(require,module,exports){
  2876. module.exports = ConeTwistConstraint;
  2877. var Constraint = require('./Constraint');
  2878. var PointToPointConstraint = require('./PointToPointConstraint');
  2879. var ConeEquation = require('../equations/ConeEquation');
  2880. var RotationalEquation = require('../equations/RotationalEquation');
  2881. var ContactEquation = require('../equations/ContactEquation');
  2882. var Vec3 = require('../math/Vec3');
  2883. /**
  2884. * @class ConeTwistConstraint
  2885. * @constructor
  2886. * @author schteppe
  2887. * @param {Body} bodyA
  2888. * @param {Body} bodyB
  2889. * @param {object} [options]
  2890. * @param {Vec3} [options.pivotA]
  2891. * @param {Vec3} [options.pivotB]
  2892. * @param {Vec3} [options.axisA]
  2893. * @param {Vec3} [options.axisB]
  2894. * @param {Number} [options.maxForce=1e6]
  2895. * @extends PointToPointConstraint
  2896. */
  2897. function ConeTwistConstraint(bodyA, bodyB, options){
  2898. options = options || {};
  2899. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  2900. // Set pivot point in between
  2901. var pivotA = options.pivotA ? options.pivotA.clone() : new Vec3();
  2902. var pivotB = options.pivotB ? options.pivotB.clone() : new Vec3();
  2903. this.axisA = options.axisA ? options.axisA.clone() : new Vec3();
  2904. this.axisB = options.axisB ? options.axisB.clone() : new Vec3();
  2905. PointToPointConstraint.call(this, bodyA, pivotA, bodyB, pivotB, maxForce);
  2906. this.collideConnected = !!options.collideConnected;
  2907. this.angle = typeof(options.angle) !== 'undefined' ? options.angle : 0;
  2908. /**
  2909. * @property {ConeEquation} coneEquation
  2910. */
  2911. var c = this.coneEquation = new ConeEquation(bodyA,bodyB,options);
  2912. /**
  2913. * @property {RotationalEquation} twistEquation
  2914. */
  2915. var t = this.twistEquation = new RotationalEquation(bodyA,bodyB,options);
  2916. this.twistAngle = typeof(options.twistAngle) !== 'undefined' ? options.twistAngle : 0;
  2917. // Make the cone equation push the bodies toward the cone axis, not outward
  2918. c.maxForce = 0;
  2919. c.minForce = -maxForce;
  2920. // Make the twist equation add torque toward the initial position
  2921. t.maxForce = 0;
  2922. t.minForce = -maxForce;
  2923. this.equations.push(c, t);
  2924. }
  2925. ConeTwistConstraint.prototype = new PointToPointConstraint();
  2926. ConeTwistConstraint.constructor = ConeTwistConstraint;
  2927. var ConeTwistConstraint_update_tmpVec1 = new Vec3();
  2928. var ConeTwistConstraint_update_tmpVec2 = new Vec3();
  2929. ConeTwistConstraint.prototype.update = function(){
  2930. var bodyA = this.bodyA,
  2931. bodyB = this.bodyB,
  2932. cone = this.coneEquation,
  2933. twist = this.twistEquation;
  2934. PointToPointConstraint.prototype.update.call(this);
  2935. // Update the axes to the cone constraint
  2936. bodyA.vectorToWorldFrame(this.axisA, cone.axisA);
  2937. bodyB.vectorToWorldFrame(this.axisB, cone.axisB);
  2938. // Update the world axes in the twist constraint
  2939. this.axisA.tangents(twist.axisA, twist.axisA);
  2940. bodyA.vectorToWorldFrame(twist.axisA, twist.axisA);
  2941. this.axisB.tangents(twist.axisB, twist.axisB);
  2942. bodyB.vectorToWorldFrame(twist.axisB, twist.axisB);
  2943. cone.angle = this.angle;
  2944. twist.maxAngle = this.twistAngle;
  2945. };
  2946. },{"../equations/ConeEquation":31,"../equations/ContactEquation":32,"../equations/RotationalEquation":35,"../math/Vec3":43,"./Constraint":26,"./PointToPointConstraint":30}],26:[function(require,module,exports){
  2947. module.exports = Constraint;
  2948. var Utils = require('../utils/Utils');
  2949. /**
  2950. * Constraint base class
  2951. * @class Constraint
  2952. * @author schteppe
  2953. * @constructor
  2954. * @param {Body} bodyA
  2955. * @param {Body} bodyB
  2956. * @param {object} [options]
  2957. * @param {boolean} [options.collideConnected=true]
  2958. * @param {boolean} [options.wakeUpBodies=true]
  2959. */
  2960. function Constraint(bodyA, bodyB, options){
  2961. options = Utils.defaults(options,{
  2962. collideConnected : true,
  2963. wakeUpBodies : true,
  2964. });
  2965. /**
  2966. * Equations to be solved in this constraint
  2967. * @property equations
  2968. * @type {Array}
  2969. */
  2970. this.equations = [];
  2971. /**
  2972. * @property {Body} bodyA
  2973. */
  2974. this.bodyA = bodyA;
  2975. /**
  2976. * @property {Body} bodyB
  2977. */
  2978. this.bodyB = bodyB;
  2979. /**
  2980. * @property {Number} id
  2981. */
  2982. this.id = Constraint.idCounter++;
  2983. /**
  2984. * Set to true if you want the bodies to collide when they are connected.
  2985. * @property collideConnected
  2986. * @type {boolean}
  2987. */
  2988. this.collideConnected = options.collideConnected;
  2989. if(options.wakeUpBodies){
  2990. if(bodyA){
  2991. bodyA.wakeUp();
  2992. }
  2993. if(bodyB){
  2994. bodyB.wakeUp();
  2995. }
  2996. }
  2997. }
  2998. /**
  2999. * Update all the equations with data.
  3000. * @method update
  3001. */
  3002. Constraint.prototype.update = function(){
  3003. throw new Error("method update() not implmemented in this Constraint subclass!");
  3004. };
  3005. /**
  3006. * Enables all equations in the constraint.
  3007. * @method enable
  3008. */
  3009. Constraint.prototype.enable = function(){
  3010. var eqs = this.equations;
  3011. for(var i=0; i<eqs.length; i++){
  3012. eqs[i].enabled = true;
  3013. }
  3014. };
  3015. /**
  3016. * Disables all equations in the constraint.
  3017. * @method disable
  3018. */
  3019. Constraint.prototype.disable = function(){
  3020. var eqs = this.equations;
  3021. for(var i=0; i<eqs.length; i++){
  3022. eqs[i].enabled = false;
  3023. }
  3024. };
  3025. Constraint.idCounter = 0;
  3026. },{"../utils/Utils":66}],27:[function(require,module,exports){
  3027. module.exports = DistanceConstraint;
  3028. var Constraint = require('./Constraint');
  3029. var ContactEquation = require('../equations/ContactEquation');
  3030. /**
  3031. * Constrains two bodies to be at a constant distance from each others center of mass.
  3032. * @class DistanceConstraint
  3033. * @constructor
  3034. * @author schteppe
  3035. * @param {Body} bodyA
  3036. * @param {Body} bodyB
  3037. * @param {Number} [distance] The distance to keep. If undefined, it will be set to the current distance between bodyA and bodyB
  3038. * @param {Number} [maxForce=1e6]
  3039. * @extends Constraint
  3040. */
  3041. function DistanceConstraint(bodyA,bodyB,distance,maxForce){
  3042. Constraint.call(this,bodyA,bodyB);
  3043. if(typeof(distance)==="undefined") {
  3044. distance = bodyA.position.distanceTo(bodyB.position);
  3045. }
  3046. if(typeof(maxForce)==="undefined") {
  3047. maxForce = 1e6;
  3048. }
  3049. /**
  3050. * @property {number} distance
  3051. */
  3052. this.distance = distance;
  3053. /**
  3054. * @property {ContactEquation} distanceEquation
  3055. */
  3056. var eq = this.distanceEquation = new ContactEquation(bodyA, bodyB);
  3057. this.equations.push(eq);
  3058. // Make it bidirectional
  3059. eq.minForce = -maxForce;
  3060. eq.maxForce = maxForce;
  3061. }
  3062. DistanceConstraint.prototype = new Constraint();
  3063. DistanceConstraint.prototype.update = function(){
  3064. var bodyA = this.bodyA;
  3065. var bodyB = this.bodyB;
  3066. var eq = this.distanceEquation;
  3067. var halfDist = this.distance * 0.5;
  3068. var normal = eq.ni;
  3069. bodyB.position.vsub(bodyA.position, normal);
  3070. normal.normalize();
  3071. normal.mult(halfDist, eq.ri);
  3072. normal.mult(-halfDist, eq.rj);
  3073. };
  3074. },{"../equations/ContactEquation":32,"./Constraint":26}],28:[function(require,module,exports){
  3075. module.exports = HingeConstraint;
  3076. var Constraint = require('./Constraint');
  3077. var PointToPointConstraint = require('./PointToPointConstraint');
  3078. var RotationalEquation = require('../equations/RotationalEquation');
  3079. var RotationalMotorEquation = require('../equations/RotationalMotorEquation');
  3080. var ContactEquation = require('../equations/ContactEquation');
  3081. var Vec3 = require('../math/Vec3');
  3082. /**
  3083. * Hinge constraint. Think of it as a door hinge. It tries to keep the door in the correct place and with the correct orientation.
  3084. * @class HingeConstraint
  3085. * @constructor
  3086. * @author schteppe
  3087. * @param {Body} bodyA
  3088. * @param {Body} bodyB
  3089. * @param {object} [options]
  3090. * @param {Vec3} [options.pivotA] A point defined locally in bodyA. This defines the offset of axisA.
  3091. * @param {Vec3} [options.axisA] An axis that bodyA can rotate around, defined locally in bodyA.
  3092. * @param {Vec3} [options.pivotB]
  3093. * @param {Vec3} [options.axisB]
  3094. * @param {Number} [options.maxForce=1e6]
  3095. * @extends PointToPointConstraint
  3096. */
  3097. function HingeConstraint(bodyA, bodyB, options){
  3098. options = options || {};
  3099. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  3100. var pivotA = options.pivotA ? options.pivotA.clone() : new Vec3();
  3101. var pivotB = options.pivotB ? options.pivotB.clone() : new Vec3();
  3102. PointToPointConstraint.call(this, bodyA, pivotA, bodyB, pivotB, maxForce);
  3103. /**
  3104. * Rotation axis, defined locally in bodyA.
  3105. * @property {Vec3} axisA
  3106. */
  3107. var axisA = this.axisA = options.axisA ? options.axisA.clone() : new Vec3(1,0,0);
  3108. axisA.normalize();
  3109. /**
  3110. * Rotation axis, defined locally in bodyB.
  3111. * @property {Vec3} axisB
  3112. */
  3113. var axisB = this.axisB = options.axisB ? options.axisB.clone() : new Vec3(1,0,0);
  3114. axisB.normalize();
  3115. /**
  3116. * @property {RotationalEquation} rotationalEquation1
  3117. */
  3118. var r1 = this.rotationalEquation1 = new RotationalEquation(bodyA,bodyB,options);
  3119. /**
  3120. * @property {RotationalEquation} rotationalEquation2
  3121. */
  3122. var r2 = this.rotationalEquation2 = new RotationalEquation(bodyA,bodyB,options);
  3123. /**
  3124. * @property {RotationalMotorEquation} motorEquation
  3125. */
  3126. var motor = this.motorEquation = new RotationalMotorEquation(bodyA,bodyB,maxForce);
  3127. motor.enabled = false; // Not enabled by default
  3128. // Equations to be fed to the solver
  3129. this.equations.push(
  3130. r1, // rotational1
  3131. r2, // rotational2
  3132. motor
  3133. );
  3134. }
  3135. HingeConstraint.prototype = new PointToPointConstraint();
  3136. HingeConstraint.constructor = HingeConstraint;
  3137. /**
  3138. * @method enableMotor
  3139. */
  3140. HingeConstraint.prototype.enableMotor = function(){
  3141. this.motorEquation.enabled = true;
  3142. };
  3143. /**
  3144. * @method disableMotor
  3145. */
  3146. HingeConstraint.prototype.disableMotor = function(){
  3147. this.motorEquation.enabled = false;
  3148. };
  3149. /**
  3150. * @method setMotorSpeed
  3151. * @param {number} speed
  3152. */
  3153. HingeConstraint.prototype.setMotorSpeed = function(speed){
  3154. this.motorEquation.targetVelocity = speed;
  3155. };
  3156. /**
  3157. * @method setMotorMaxForce
  3158. * @param {number} maxForce
  3159. */
  3160. HingeConstraint.prototype.setMotorMaxForce = function(maxForce){
  3161. this.motorEquation.maxForce = maxForce;
  3162. this.motorEquation.minForce = -maxForce;
  3163. };
  3164. var HingeConstraint_update_tmpVec1 = new Vec3();
  3165. var HingeConstraint_update_tmpVec2 = new Vec3();
  3166. HingeConstraint.prototype.update = function(){
  3167. var bodyA = this.bodyA,
  3168. bodyB = this.bodyB,
  3169. motor = this.motorEquation,
  3170. r1 = this.rotationalEquation1,
  3171. r2 = this.rotationalEquation2,
  3172. worldAxisA = HingeConstraint_update_tmpVec1,
  3173. worldAxisB = HingeConstraint_update_tmpVec2;
  3174. var axisA = this.axisA;
  3175. var axisB = this.axisB;
  3176. PointToPointConstraint.prototype.update.call(this);
  3177. // Get world axes
  3178. bodyA.quaternion.vmult(axisA, worldAxisA);
  3179. bodyB.quaternion.vmult(axisB, worldAxisB);
  3180. worldAxisA.tangents(r1.axisA, r2.axisA);
  3181. r1.axisB.copy(worldAxisB);
  3182. r2.axisB.copy(worldAxisB);
  3183. if(this.motorEquation.enabled){
  3184. bodyA.quaternion.vmult(this.axisA, motor.axisA);
  3185. bodyB.quaternion.vmult(this.axisB, motor.axisB);
  3186. }
  3187. };
  3188. },{"../equations/ContactEquation":32,"../equations/RotationalEquation":35,"../equations/RotationalMotorEquation":36,"../math/Vec3":43,"./Constraint":26,"./PointToPointConstraint":30}],29:[function(require,module,exports){
  3189. module.exports = LockConstraint;
  3190. var Constraint = require('./Constraint');
  3191. var PointToPointConstraint = require('./PointToPointConstraint');
  3192. var RotationalEquation = require('../equations/RotationalEquation');
  3193. var RotationalMotorEquation = require('../equations/RotationalMotorEquation');
  3194. var ContactEquation = require('../equations/ContactEquation');
  3195. var Vec3 = require('../math/Vec3');
  3196. /**
  3197. * Lock constraint. Will remove all degrees of freedom between the bodies.
  3198. * @class LockConstraint
  3199. * @constructor
  3200. * @author schteppe
  3201. * @param {Body} bodyA
  3202. * @param {Body} bodyB
  3203. * @param {object} [options]
  3204. * @param {Number} [options.maxForce=1e6]
  3205. * @extends PointToPointConstraint
  3206. */
  3207. function LockConstraint(bodyA, bodyB, options){
  3208. options = options || {};
  3209. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  3210. // Set pivot point in between
  3211. var pivotA = new Vec3();
  3212. var pivotB = new Vec3();
  3213. var halfWay = new Vec3();
  3214. bodyA.position.vadd(bodyB.position, halfWay);
  3215. halfWay.scale(0.5, halfWay);
  3216. bodyB.pointToLocalFrame(halfWay, pivotB);
  3217. bodyA.pointToLocalFrame(halfWay, pivotA);
  3218. // The point-to-point constraint will keep a point shared between the bodies
  3219. PointToPointConstraint.call(this, bodyA, pivotA, bodyB, pivotB, maxForce);
  3220. // Store initial rotation of the bodies as unit vectors in the local body spaces
  3221. this.xA = bodyA.vectorToLocalFrame(Vec3.UNIT_X);
  3222. this.xB = bodyB.vectorToLocalFrame(Vec3.UNIT_X);
  3223. this.yA = bodyA.vectorToLocalFrame(Vec3.UNIT_Y);
  3224. this.yB = bodyB.vectorToLocalFrame(Vec3.UNIT_Y);
  3225. this.zA = bodyA.vectorToLocalFrame(Vec3.UNIT_Z);
  3226. this.zB = bodyB.vectorToLocalFrame(Vec3.UNIT_Z);
  3227. // ...and the following rotational equations will keep all rotational DOF's in place
  3228. /**
  3229. * @property {RotationalEquation} rotationalEquation1
  3230. */
  3231. var r1 = this.rotationalEquation1 = new RotationalEquation(bodyA,bodyB,options);
  3232. /**
  3233. * @property {RotationalEquation} rotationalEquation2
  3234. */
  3235. var r2 = this.rotationalEquation2 = new RotationalEquation(bodyA,bodyB,options);
  3236. /**
  3237. * @property {RotationalEquation} rotationalEquation3
  3238. */
  3239. var r3 = this.rotationalEquation3 = new RotationalEquation(bodyA,bodyB,options);
  3240. this.equations.push(r1, r2, r3);
  3241. }
  3242. LockConstraint.prototype = new PointToPointConstraint();
  3243. LockConstraint.constructor = LockConstraint;
  3244. var LockConstraint_update_tmpVec1 = new Vec3();
  3245. var LockConstraint_update_tmpVec2 = new Vec3();
  3246. LockConstraint.prototype.update = function(){
  3247. var bodyA = this.bodyA,
  3248. bodyB = this.bodyB,
  3249. motor = this.motorEquation,
  3250. r1 = this.rotationalEquation1,
  3251. r2 = this.rotationalEquation2,
  3252. r3 = this.rotationalEquation3,
  3253. worldAxisA = LockConstraint_update_tmpVec1,
  3254. worldAxisB = LockConstraint_update_tmpVec2;
  3255. PointToPointConstraint.prototype.update.call(this);
  3256. // These vector pairs must be orthogonal
  3257. bodyA.vectorToWorldFrame(this.xA, r1.axisA);
  3258. bodyB.vectorToWorldFrame(this.yB, r1.axisB);
  3259. bodyA.vectorToWorldFrame(this.yA, r2.axisA);
  3260. bodyB.vectorToWorldFrame(this.zB, r2.axisB);
  3261. bodyA.vectorToWorldFrame(this.zA, r3.axisA);
  3262. bodyB.vectorToWorldFrame(this.xB, r3.axisB);
  3263. };
  3264. },{"../equations/ContactEquation":32,"../equations/RotationalEquation":35,"../equations/RotationalMotorEquation":36,"../math/Vec3":43,"./Constraint":26,"./PointToPointConstraint":30}],30:[function(require,module,exports){
  3265. module.exports = PointToPointConstraint;
  3266. var Constraint = require('./Constraint');
  3267. var ContactEquation = require('../equations/ContactEquation');
  3268. var Vec3 = require('../math/Vec3');
  3269. /**
  3270. * Connects two bodies at given offset points.
  3271. * @class PointToPointConstraint
  3272. * @extends Constraint
  3273. * @constructor
  3274. * @param {Body} bodyA
  3275. * @param {Vec3} pivotA The point relative to the center of mass of bodyA which bodyA is constrained to.
  3276. * @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.
  3277. * @param {Vec3} pivotB See pivotA.
  3278. * @param {Number} maxForce The maximum force that should be applied to constrain the bodies.
  3279. *
  3280. * @example
  3281. * var bodyA = new Body({ mass: 1 });
  3282. * var bodyB = new Body({ mass: 1 });
  3283. * bodyA.position.set(-1, 0, 0);
  3284. * bodyB.position.set(1, 0, 0);
  3285. * bodyA.addShape(shapeA);
  3286. * bodyB.addShape(shapeB);
  3287. * world.addBody(bodyA);
  3288. * world.addBody(bodyB);
  3289. * var localPivotA = new Vec3(1, 0, 0);
  3290. * var localPivotB = new Vec3(-1, 0, 0);
  3291. * var constraint = new PointToPointConstraint(bodyA, localPivotA, bodyB, localPivotB);
  3292. * world.addConstraint(constraint);
  3293. */
  3294. function PointToPointConstraint(bodyA,pivotA,bodyB,pivotB,maxForce){
  3295. Constraint.call(this,bodyA,bodyB);
  3296. maxForce = typeof(maxForce) !== 'undefined' ? maxForce : 1e6;
  3297. /**
  3298. * Pivot, defined locally in bodyA.
  3299. * @property {Vec3} pivotA
  3300. */
  3301. this.pivotA = pivotA ? pivotA.clone() : new Vec3();
  3302. /**
  3303. * Pivot, defined locally in bodyB.
  3304. * @property {Vec3} pivotB
  3305. */
  3306. this.pivotB = pivotB ? pivotB.clone() : new Vec3();
  3307. /**
  3308. * @property {ContactEquation} equationX
  3309. */
  3310. var x = this.equationX = new ContactEquation(bodyA,bodyB);
  3311. /**
  3312. * @property {ContactEquation} equationY
  3313. */
  3314. var y = this.equationY = new ContactEquation(bodyA,bodyB);
  3315. /**
  3316. * @property {ContactEquation} equationZ
  3317. */
  3318. var z = this.equationZ = new ContactEquation(bodyA,bodyB);
  3319. // Equations to be fed to the solver
  3320. this.equations.push(x, y, z);
  3321. // Make the equations bidirectional
  3322. x.minForce = y.minForce = z.minForce = -maxForce;
  3323. x.maxForce = y.maxForce = z.maxForce = maxForce;
  3324. x.ni.set(1, 0, 0);
  3325. y.ni.set(0, 1, 0);
  3326. z.ni.set(0, 0, 1);
  3327. }
  3328. PointToPointConstraint.prototype = new Constraint();
  3329. PointToPointConstraint.prototype.update = function(){
  3330. var bodyA = this.bodyA;
  3331. var bodyB = this.bodyB;
  3332. var x = this.equationX;
  3333. var y = this.equationY;
  3334. var z = this.equationZ;
  3335. // Rotate the pivots to world space
  3336. bodyA.quaternion.vmult(this.pivotA,x.ri);
  3337. bodyB.quaternion.vmult(this.pivotB,x.rj);
  3338. y.ri.copy(x.ri);
  3339. y.rj.copy(x.rj);
  3340. z.ri.copy(x.ri);
  3341. z.rj.copy(x.rj);
  3342. };
  3343. },{"../equations/ContactEquation":32,"../math/Vec3":43,"./Constraint":26}],31:[function(require,module,exports){
  3344. module.exports = ConeEquation;
  3345. var Vec3 = require('../math/Vec3');
  3346. var Mat3 = require('../math/Mat3');
  3347. var Equation = require('./Equation');
  3348. /**
  3349. * Cone equation. Works to keep the given body world vectors aligned, or tilted within a given angle from each other.
  3350. * @class ConeEquation
  3351. * @constructor
  3352. * @author schteppe
  3353. * @param {Body} bodyA
  3354. * @param {Body} bodyB
  3355. * @param {Vec3} [options.axisA] Local axis in A
  3356. * @param {Vec3} [options.axisB] Local axis in B
  3357. * @param {Vec3} [options.angle] The "cone angle" to keep
  3358. * @param {number} [options.maxForce=1e6]
  3359. * @extends Equation
  3360. */
  3361. function ConeEquation(bodyA, bodyB, options){
  3362. options = options || {};
  3363. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  3364. Equation.call(this,bodyA,bodyB,-maxForce, maxForce);
  3365. this.axisA = options.axisA ? options.axisA.clone() : new Vec3(1, 0, 0);
  3366. this.axisB = options.axisB ? options.axisB.clone() : new Vec3(0, 1, 0);
  3367. /**
  3368. * The cone angle to keep
  3369. * @property {number} angle
  3370. */
  3371. this.angle = typeof(options.angle) !== 'undefined' ? options.angle : 0;
  3372. }
  3373. ConeEquation.prototype = new Equation();
  3374. ConeEquation.prototype.constructor = ConeEquation;
  3375. var tmpVec1 = new Vec3();
  3376. var tmpVec2 = new Vec3();
  3377. ConeEquation.prototype.computeB = function(h){
  3378. var a = this.a,
  3379. b = this.b,
  3380. ni = this.axisA,
  3381. nj = this.axisB,
  3382. nixnj = tmpVec1,
  3383. njxni = tmpVec2,
  3384. GA = this.jacobianElementA,
  3385. GB = this.jacobianElementB;
  3386. // Caluclate cross products
  3387. ni.cross(nj, nixnj);
  3388. nj.cross(ni, njxni);
  3389. // The angle between two vector is:
  3390. // cos(theta) = a * b / (length(a) * length(b) = { len(a) = len(b) = 1 } = a * b
  3391. // g = a * b
  3392. // gdot = (b x a) * wi + (a x b) * wj
  3393. // G = [0 bxa 0 axb]
  3394. // W = [vi wi vj wj]
  3395. GA.rotational.copy(njxni);
  3396. GB.rotational.copy(nixnj);
  3397. var g = Math.cos(this.angle) - ni.dot(nj),
  3398. GW = this.computeGW(),
  3399. GiMf = this.computeGiMf();
  3400. var B = - g * a - GW * b - h * GiMf;
  3401. return B;
  3402. };
  3403. },{"../math/Mat3":40,"../math/Vec3":43,"./Equation":33}],32:[function(require,module,exports){
  3404. module.exports = ContactEquation;
  3405. var Equation = require('./Equation');
  3406. var Vec3 = require('../math/Vec3');
  3407. var Mat3 = require('../math/Mat3');
  3408. /**
  3409. * Contact/non-penetration constraint equation
  3410. * @class ContactEquation
  3411. * @constructor
  3412. * @author schteppe
  3413. * @param {Body} bodyA
  3414. * @param {Body} bodyB
  3415. * @extends Equation
  3416. */
  3417. function ContactEquation(bodyA, bodyB, maxForce){
  3418. maxForce = typeof(maxForce) !== 'undefined' ? maxForce : 1e6;
  3419. Equation.call(this, bodyA, bodyB, 0, maxForce);
  3420. /**
  3421. * @property restitution
  3422. * @type {Number}
  3423. */
  3424. this.restitution = 0.0; // "bounciness": u1 = -e*u0
  3425. /**
  3426. * World-oriented vector that goes from the center of bi to the contact point.
  3427. * @property {Vec3} ri
  3428. */
  3429. this.ri = new Vec3();
  3430. /**
  3431. * World-oriented vector that starts in body j position and goes to the contact point.
  3432. * @property {Vec3} rj
  3433. */
  3434. this.rj = new Vec3();
  3435. /**
  3436. * Contact normal, pointing out of body i.
  3437. * @property {Vec3} ni
  3438. */
  3439. this.ni = new Vec3();
  3440. }
  3441. ContactEquation.prototype = new Equation();
  3442. ContactEquation.prototype.constructor = ContactEquation;
  3443. var ContactEquation_computeB_temp1 = new Vec3(); // Temp vectors
  3444. var ContactEquation_computeB_temp2 = new Vec3();
  3445. var ContactEquation_computeB_temp3 = new Vec3();
  3446. ContactEquation.prototype.computeB = function(h){
  3447. var a = this.a,
  3448. b = this.b,
  3449. bi = this.bi,
  3450. bj = this.bj,
  3451. ri = this.ri,
  3452. rj = this.rj,
  3453. rixn = ContactEquation_computeB_temp1,
  3454. rjxn = ContactEquation_computeB_temp2,
  3455. vi = bi.velocity,
  3456. wi = bi.angularVelocity,
  3457. fi = bi.force,
  3458. taui = bi.torque,
  3459. vj = bj.velocity,
  3460. wj = bj.angularVelocity,
  3461. fj = bj.force,
  3462. tauj = bj.torque,
  3463. penetrationVec = ContactEquation_computeB_temp3,
  3464. GA = this.jacobianElementA,
  3465. GB = this.jacobianElementB,
  3466. n = this.ni;
  3467. // Caluclate cross products
  3468. ri.cross(n,rixn);
  3469. rj.cross(n,rjxn);
  3470. // g = xj+rj -(xi+ri)
  3471. // G = [ -ni -rixn ni rjxn ]
  3472. n.negate(GA.spatial);
  3473. rixn.negate(GA.rotational);
  3474. GB.spatial.copy(n);
  3475. GB.rotational.copy(rjxn);
  3476. // Calculate the penetration vector
  3477. penetrationVec.copy(bj.position);
  3478. penetrationVec.vadd(rj,penetrationVec);
  3479. penetrationVec.vsub(bi.position,penetrationVec);
  3480. penetrationVec.vsub(ri,penetrationVec);
  3481. var g = n.dot(penetrationVec);
  3482. // Compute iteration
  3483. var ePlusOne = this.restitution + 1;
  3484. var GW = ePlusOne * vj.dot(n) - ePlusOne * vi.dot(n) + wj.dot(rjxn) - wi.dot(rixn);
  3485. var GiMf = this.computeGiMf();
  3486. var B = - g * a - GW * b - h*GiMf;
  3487. return B;
  3488. };
  3489. var ContactEquation_getImpactVelocityAlongNormal_vi = new Vec3();
  3490. var ContactEquation_getImpactVelocityAlongNormal_vj = new Vec3();
  3491. var ContactEquation_getImpactVelocityAlongNormal_xi = new Vec3();
  3492. var ContactEquation_getImpactVelocityAlongNormal_xj = new Vec3();
  3493. var ContactEquation_getImpactVelocityAlongNormal_relVel = new Vec3();
  3494. /**
  3495. * Get the current relative velocity in the contact point.
  3496. * @method getImpactVelocityAlongNormal
  3497. * @return {number}
  3498. */
  3499. ContactEquation.prototype.getImpactVelocityAlongNormal = function(){
  3500. var vi = ContactEquation_getImpactVelocityAlongNormal_vi;
  3501. var vj = ContactEquation_getImpactVelocityAlongNormal_vj;
  3502. var xi = ContactEquation_getImpactVelocityAlongNormal_xi;
  3503. var xj = ContactEquation_getImpactVelocityAlongNormal_xj;
  3504. var relVel = ContactEquation_getImpactVelocityAlongNormal_relVel;
  3505. this.bi.position.vadd(this.ri, xi);
  3506. this.bj.position.vadd(this.rj, xj);
  3507. this.bi.getVelocityAtWorldPoint(xi, vi);
  3508. this.bj.getVelocityAtWorldPoint(xj, vj);
  3509. vi.vsub(vj, relVel);
  3510. return this.ni.dot(relVel);
  3511. };
  3512. },{"../math/Mat3":40,"../math/Vec3":43,"./Equation":33}],33:[function(require,module,exports){
  3513. module.exports = Equation;
  3514. var JacobianElement = require('../math/JacobianElement'),
  3515. Vec3 = require('../math/Vec3');
  3516. /**
  3517. * Equation base class
  3518. * @class Equation
  3519. * @constructor
  3520. * @author schteppe
  3521. * @param {Body} bi
  3522. * @param {Body} bj
  3523. * @param {Number} minForce Minimum (read: negative max) force to be applied by the constraint.
  3524. * @param {Number} maxForce Maximum (read: positive max) force to be applied by the constraint.
  3525. */
  3526. function Equation(bi,bj,minForce,maxForce){
  3527. this.id = Equation.id++;
  3528. /**
  3529. * @property {number} minForce
  3530. */
  3531. this.minForce = typeof(minForce)==="undefined" ? -1e6 : minForce;
  3532. /**
  3533. * @property {number} maxForce
  3534. */
  3535. this.maxForce = typeof(maxForce)==="undefined" ? 1e6 : maxForce;
  3536. /**
  3537. * @property bi
  3538. * @type {Body}
  3539. */
  3540. this.bi = bi;
  3541. /**
  3542. * @property bj
  3543. * @type {Body}
  3544. */
  3545. this.bj = bj;
  3546. /**
  3547. * SPOOK parameter
  3548. * @property {number} a
  3549. */
  3550. this.a = 0.0;
  3551. /**
  3552. * SPOOK parameter
  3553. * @property {number} b
  3554. */
  3555. this.b = 0.0;
  3556. /**
  3557. * SPOOK parameter
  3558. * @property {number} eps
  3559. */
  3560. this.eps = 0.0;
  3561. /**
  3562. * @property {JacobianElement} jacobianElementA
  3563. */
  3564. this.jacobianElementA = new JacobianElement();
  3565. /**
  3566. * @property {JacobianElement} jacobianElementB
  3567. */
  3568. this.jacobianElementB = new JacobianElement();
  3569. /**
  3570. * @property {boolean} enabled
  3571. * @default true
  3572. */
  3573. this.enabled = true;
  3574. /**
  3575. * A number, proportional to the force added to the bodies.
  3576. * @property {number} multiplier
  3577. * @readonly
  3578. */
  3579. this.multiplier = 0;
  3580. // Set typical spook params
  3581. this.setSpookParams(1e7,4,1/60);
  3582. }
  3583. Equation.prototype.constructor = Equation;
  3584. Equation.id = 0;
  3585. /**
  3586. * Recalculates a,b,eps.
  3587. * @method setSpookParams
  3588. */
  3589. Equation.prototype.setSpookParams = function(stiffness,relaxation,timeStep){
  3590. var d = relaxation,
  3591. k = stiffness,
  3592. h = timeStep;
  3593. this.a = 4.0 / (h * (1 + 4 * d));
  3594. this.b = (4.0 * d) / (1 + 4 * d);
  3595. this.eps = 4.0 / (h * h * k * (1 + 4 * d));
  3596. };
  3597. /**
  3598. * Computes the RHS of the SPOOK equation
  3599. * @method computeB
  3600. * @return {Number}
  3601. */
  3602. Equation.prototype.computeB = function(a,b,h){
  3603. var GW = this.computeGW(),
  3604. Gq = this.computeGq(),
  3605. GiMf = this.computeGiMf();
  3606. return - Gq * a - GW * b - GiMf*h;
  3607. };
  3608. /**
  3609. * Computes G*q, where q are the generalized body coordinates
  3610. * @method computeGq
  3611. * @return {Number}
  3612. */
  3613. Equation.prototype.computeGq = function(){
  3614. var GA = this.jacobianElementA,
  3615. GB = this.jacobianElementB,
  3616. bi = this.bi,
  3617. bj = this.bj,
  3618. xi = bi.position,
  3619. xj = bj.position;
  3620. return GA.spatial.dot(xi) + GB.spatial.dot(xj);
  3621. };
  3622. var zero = new Vec3();
  3623. /**
  3624. * Computes G*W, where W are the body velocities
  3625. * @method computeGW
  3626. * @return {Number}
  3627. */
  3628. Equation.prototype.computeGW = function(){
  3629. var GA = this.jacobianElementA,
  3630. GB = this.jacobianElementB,
  3631. bi = this.bi,
  3632. bj = this.bj,
  3633. vi = bi.velocity,
  3634. vj = bj.velocity,
  3635. wi = bi.angularVelocity,
  3636. wj = bj.angularVelocity;
  3637. return GA.multiplyVectors(vi,wi) + GB.multiplyVectors(vj,wj);
  3638. };
  3639. /**
  3640. * Computes G*Wlambda, where W are the body velocities
  3641. * @method computeGWlambda
  3642. * @return {Number}
  3643. */
  3644. Equation.prototype.computeGWlambda = function(){
  3645. var GA = this.jacobianElementA,
  3646. GB = this.jacobianElementB,
  3647. bi = this.bi,
  3648. bj = this.bj,
  3649. vi = bi.vlambda,
  3650. vj = bj.vlambda,
  3651. wi = bi.wlambda,
  3652. wj = bj.wlambda;
  3653. return GA.multiplyVectors(vi,wi) + GB.multiplyVectors(vj,wj);
  3654. };
  3655. /**
  3656. * 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.
  3657. * @method computeGiMf
  3658. * @return {Number}
  3659. */
  3660. var iMfi = new Vec3(),
  3661. iMfj = new Vec3(),
  3662. invIi_vmult_taui = new Vec3(),
  3663. invIj_vmult_tauj = new Vec3();
  3664. Equation.prototype.computeGiMf = function(){
  3665. var GA = this.jacobianElementA,
  3666. GB = this.jacobianElementB,
  3667. bi = this.bi,
  3668. bj = this.bj,
  3669. fi = bi.force,
  3670. ti = bi.torque,
  3671. fj = bj.force,
  3672. tj = bj.torque,
  3673. invMassi = bi.invMassSolve,
  3674. invMassj = bj.invMassSolve;
  3675. fi.scale(invMassi,iMfi);
  3676. fj.scale(invMassj,iMfj);
  3677. bi.invInertiaWorldSolve.vmult(ti,invIi_vmult_taui);
  3678. bj.invInertiaWorldSolve.vmult(tj,invIj_vmult_tauj);
  3679. return GA.multiplyVectors(iMfi,invIi_vmult_taui) + GB.multiplyVectors(iMfj,invIj_vmult_tauj);
  3680. };
  3681. /**
  3682. * Computes G*inv(M)*G'
  3683. * @method computeGiMGt
  3684. * @return {Number}
  3685. */
  3686. var tmp = new Vec3();
  3687. Equation.prototype.computeGiMGt = function(){
  3688. var GA = this.jacobianElementA,
  3689. GB = this.jacobianElementB,
  3690. bi = this.bi,
  3691. bj = this.bj,
  3692. invMassi = bi.invMassSolve,
  3693. invMassj = bj.invMassSolve,
  3694. invIi = bi.invInertiaWorldSolve,
  3695. invIj = bj.invInertiaWorldSolve,
  3696. result = invMassi + invMassj;
  3697. invIi.vmult(GA.rotational,tmp);
  3698. result += tmp.dot(GA.rotational);
  3699. invIj.vmult(GB.rotational,tmp);
  3700. result += tmp.dot(GB.rotational);
  3701. return result;
  3702. };
  3703. var addToWlambda_temp = new Vec3(),
  3704. addToWlambda_Gi = new Vec3(),
  3705. addToWlambda_Gj = new Vec3(),
  3706. addToWlambda_ri = new Vec3(),
  3707. addToWlambda_rj = new Vec3(),
  3708. addToWlambda_Mdiag = new Vec3();
  3709. /**
  3710. * Add constraint velocity to the bodies.
  3711. * @method addToWlambda
  3712. * @param {Number} deltalambda
  3713. */
  3714. Equation.prototype.addToWlambda = function(deltalambda){
  3715. var GA = this.jacobianElementA,
  3716. GB = this.jacobianElementB,
  3717. bi = this.bi,
  3718. bj = this.bj,
  3719. temp = addToWlambda_temp;
  3720. // Add to linear velocity
  3721. // v_lambda += inv(M) * delta_lamba * G
  3722. bi.vlambda.addScaledVector(bi.invMassSolve * deltalambda, GA.spatial, bi.vlambda);
  3723. bj.vlambda.addScaledVector(bj.invMassSolve * deltalambda, GB.spatial, bj.vlambda);
  3724. // Add to angular velocity
  3725. bi.invInertiaWorldSolve.vmult(GA.rotational,temp);
  3726. bi.wlambda.addScaledVector(deltalambda, temp, bi.wlambda);
  3727. bj.invInertiaWorldSolve.vmult(GB.rotational,temp);
  3728. bj.wlambda.addScaledVector(deltalambda, temp, bj.wlambda);
  3729. };
  3730. /**
  3731. * Compute the denominator part of the SPOOK equation: C = G*inv(M)*G' + eps
  3732. * @method computeInvC
  3733. * @param {Number} eps
  3734. * @return {Number}
  3735. */
  3736. Equation.prototype.computeC = function(){
  3737. return this.computeGiMGt() + this.eps;
  3738. };
  3739. },{"../math/JacobianElement":39,"../math/Vec3":43}],34:[function(require,module,exports){
  3740. module.exports = FrictionEquation;
  3741. var Equation = require('./Equation');
  3742. var Vec3 = require('../math/Vec3');
  3743. var Mat3 = require('../math/Mat3');
  3744. /**
  3745. * Constrains the slipping in a contact along a tangent
  3746. * @class FrictionEquation
  3747. * @constructor
  3748. * @author schteppe
  3749. * @param {Body} bodyA
  3750. * @param {Body} bodyB
  3751. * @param {Number} slipForce should be +-F_friction = +-mu * F_normal = +-mu * m * g
  3752. * @extends Equation
  3753. */
  3754. function FrictionEquation(bodyA, bodyB, slipForce){
  3755. Equation.call(this,bodyA, bodyB, -slipForce, slipForce);
  3756. this.ri = new Vec3();
  3757. this.rj = new Vec3();
  3758. this.t = new Vec3(); // tangent
  3759. }
  3760. FrictionEquation.prototype = new Equation();
  3761. FrictionEquation.prototype.constructor = FrictionEquation;
  3762. var FrictionEquation_computeB_temp1 = new Vec3();
  3763. var FrictionEquation_computeB_temp2 = new Vec3();
  3764. FrictionEquation.prototype.computeB = function(h){
  3765. var a = this.a,
  3766. b = this.b,
  3767. bi = this.bi,
  3768. bj = this.bj,
  3769. ri = this.ri,
  3770. rj = this.rj,
  3771. rixt = FrictionEquation_computeB_temp1,
  3772. rjxt = FrictionEquation_computeB_temp2,
  3773. t = this.t;
  3774. // Caluclate cross products
  3775. ri.cross(t,rixt);
  3776. rj.cross(t,rjxt);
  3777. // G = [-t -rixt t rjxt]
  3778. // And remember, this is a pure velocity constraint, g is always zero!
  3779. var GA = this.jacobianElementA,
  3780. GB = this.jacobianElementB;
  3781. t.negate(GA.spatial);
  3782. rixt.negate(GA.rotational);
  3783. GB.spatial.copy(t);
  3784. GB.rotational.copy(rjxt);
  3785. var GW = this.computeGW();
  3786. var GiMf = this.computeGiMf();
  3787. var B = - GW * b - h * GiMf;
  3788. return B;
  3789. };
  3790. },{"../math/Mat3":40,"../math/Vec3":43,"./Equation":33}],35:[function(require,module,exports){
  3791. module.exports = RotationalEquation;
  3792. var Vec3 = require('../math/Vec3');
  3793. var Mat3 = require('../math/Mat3');
  3794. var Equation = require('./Equation');
  3795. /**
  3796. * Rotational constraint. Works to keep the local vectors orthogonal to each other in world space.
  3797. * @class RotationalEquation
  3798. * @constructor
  3799. * @author schteppe
  3800. * @param {Body} bodyA
  3801. * @param {Body} bodyB
  3802. * @param {Vec3} [options.axisA]
  3803. * @param {Vec3} [options.axisB]
  3804. * @param {number} [options.maxForce]
  3805. * @extends Equation
  3806. */
  3807. function RotationalEquation(bodyA, bodyB, options){
  3808. options = options || {};
  3809. var maxForce = typeof(options.maxForce) !== 'undefined' ? options.maxForce : 1e6;
  3810. Equation.call(this,bodyA,bodyB,-maxForce, maxForce);
  3811. this.axisA = options.axisA ? options.axisA.clone() : new Vec3(1, 0, 0);
  3812. this.axisB = options.axisB ? options.axisB.clone() : new Vec3(0, 1, 0);
  3813. this.maxAngle = Math.PI / 2;
  3814. }
  3815. RotationalEquation.prototype = new Equation();
  3816. RotationalEquation.prototype.constructor = RotationalEquation;
  3817. var tmpVec1 = new Vec3();
  3818. var tmpVec2 = new Vec3();
  3819. RotationalEquation.prototype.computeB = function(h){
  3820. var a = this.a,
  3821. b = this.b,
  3822. ni = this.axisA,
  3823. nj = this.axisB,
  3824. nixnj = tmpVec1,
  3825. njxni = tmpVec2,
  3826. GA = this.jacobianElementA,
  3827. GB = this.jacobianElementB;
  3828. // Caluclate cross products
  3829. ni.cross(nj, nixnj);
  3830. nj.cross(ni, njxni);
  3831. // g = ni * nj
  3832. // gdot = (nj x ni) * wi + (ni x nj) * wj
  3833. // G = [0 njxni 0 nixnj]
  3834. // W = [vi wi vj wj]
  3835. GA.rotational.copy(njxni);
  3836. GB.rotational.copy(nixnj);
  3837. var g = Math.cos(this.maxAngle) - ni.dot(nj),
  3838. GW = this.computeGW(),
  3839. GiMf = this.computeGiMf();
  3840. var B = - g * a - GW * b - h * GiMf;
  3841. return B;
  3842. };
  3843. },{"../math/Mat3":40,"../math/Vec3":43,"./Equation":33}],36:[function(require,module,exports){
  3844. module.exports = RotationalMotorEquation;
  3845. var Vec3 = require('../math/Vec3');
  3846. var Mat3 = require('../math/Mat3');
  3847. var Equation = require('./Equation');
  3848. /**
  3849. * Rotational motor constraint. Tries to keep the relative angular velocity of the bodies to a given value.
  3850. * @class RotationalMotorEquation
  3851. * @constructor
  3852. * @author schteppe
  3853. * @param {Body} bodyA
  3854. * @param {Body} bodyB
  3855. * @param {Number} maxForce
  3856. * @extends Equation
  3857. */
  3858. function RotationalMotorEquation(bodyA, bodyB, maxForce){
  3859. maxForce = typeof(maxForce)!=='undefined' ? maxForce : 1e6;
  3860. Equation.call(this,bodyA,bodyB,-maxForce,maxForce);
  3861. /**
  3862. * World oriented rotational axis
  3863. * @property {Vec3} axisA
  3864. */
  3865. this.axisA = new Vec3();
  3866. /**
  3867. * World oriented rotational axis
  3868. * @property {Vec3} axisB
  3869. */
  3870. this.axisB = new Vec3(); // World oriented rotational axis
  3871. /**
  3872. * Motor velocity
  3873. * @property {Number} targetVelocity
  3874. */
  3875. this.targetVelocity = 0;
  3876. }
  3877. RotationalMotorEquation.prototype = new Equation();
  3878. RotationalMotorEquation.prototype.constructor = RotationalMotorEquation;
  3879. RotationalMotorEquation.prototype.computeB = function(h){
  3880. var a = this.a,
  3881. b = this.b,
  3882. bi = this.bi,
  3883. bj = this.bj,
  3884. axisA = this.axisA,
  3885. axisB = this.axisB,
  3886. GA = this.jacobianElementA,
  3887. GB = this.jacobianElementB;
  3888. // g = 0
  3889. // gdot = axisA * wi - axisB * wj
  3890. // gdot = G * W = G * [vi wi vj wj]
  3891. // =>
  3892. // G = [0 axisA 0 -axisB]
  3893. GA.rotational.copy(axisA);
  3894. axisB.negate(GB.rotational);
  3895. var GW = this.computeGW() - this.targetVelocity,
  3896. GiMf = this.computeGiMf();
  3897. var B = - GW * b - h * GiMf;
  3898. return B;
  3899. };
  3900. },{"../math/Mat3":40,"../math/Vec3":43,"./Equation":33}],37:[function(require,module,exports){
  3901. var Utils = require('../utils/Utils');
  3902. module.exports = ContactMaterial;
  3903. /**
  3904. * Defines what happens when two materials meet.
  3905. * @class ContactMaterial
  3906. * @constructor
  3907. * @param {Material} m1
  3908. * @param {Material} m2
  3909. * @param {object} [options]
  3910. * @param {Number} [options.friction=0.3]
  3911. * @param {Number} [options.restitution=0.3]
  3912. * @param {number} [options.contactEquationStiffness=1e7]
  3913. * @param {number} [options.contactEquationRelaxation=3]
  3914. * @param {number} [options.frictionEquationStiffness=1e7]
  3915. * @param {Number} [options.frictionEquationRelaxation=3]
  3916. */
  3917. function ContactMaterial(m1, m2, options){
  3918. options = Utils.defaults(options, {
  3919. friction: 0.3,
  3920. restitution: 0.3,
  3921. contactEquationStiffness: 1e7,
  3922. contactEquationRelaxation: 3,
  3923. frictionEquationStiffness: 1e7,
  3924. frictionEquationRelaxation: 3
  3925. });
  3926. /**
  3927. * Identifier of this material
  3928. * @property {Number} id
  3929. */
  3930. this.id = ContactMaterial.idCounter++;
  3931. /**
  3932. * Participating materials
  3933. * @property {Array} materials
  3934. * @todo Should be .materialA and .materialB instead
  3935. */
  3936. this.materials = [m1, m2];
  3937. /**
  3938. * Friction coefficient
  3939. * @property {Number} friction
  3940. */
  3941. this.friction = options.friction;
  3942. /**
  3943. * Restitution coefficient
  3944. * @property {Number} restitution
  3945. */
  3946. this.restitution = options.restitution;
  3947. /**
  3948. * Stiffness of the produced contact equations
  3949. * @property {Number} contactEquationStiffness
  3950. */
  3951. this.contactEquationStiffness = options.contactEquationStiffness;
  3952. /**
  3953. * Relaxation time of the produced contact equations
  3954. * @property {Number} contactEquationRelaxation
  3955. */
  3956. this.contactEquationRelaxation = options.contactEquationRelaxation;
  3957. /**
  3958. * Stiffness of the produced friction equations
  3959. * @property {Number} frictionEquationStiffness
  3960. */
  3961. this.frictionEquationStiffness = options.frictionEquationStiffness;
  3962. /**
  3963. * Relaxation time of the produced friction equations
  3964. * @property {Number} frictionEquationRelaxation
  3965. */
  3966. this.frictionEquationRelaxation = options.frictionEquationRelaxation;
  3967. }
  3968. ContactMaterial.idCounter = 0;
  3969. },{"../utils/Utils":66}],38:[function(require,module,exports){
  3970. module.exports = Material;
  3971. /**
  3972. * Defines a physics material.
  3973. * @class Material
  3974. * @constructor
  3975. * @param {object} [options]
  3976. * @author schteppe
  3977. */
  3978. function Material(options){
  3979. var name = '';
  3980. options = options || {};
  3981. // Backwards compatibility fix
  3982. if(typeof(options) === 'string'){
  3983. name = options;
  3984. options = {};
  3985. } else if(typeof(options) === 'object') {
  3986. name = '';
  3987. }
  3988. /**
  3989. * @property name
  3990. * @type {String}
  3991. */
  3992. this.name = name;
  3993. /**
  3994. * material id.
  3995. * @property id
  3996. * @type {number}
  3997. */
  3998. this.id = Material.idCounter++;
  3999. /**
  4000. * 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.
  4001. * @property {number} friction
  4002. */
  4003. this.friction = typeof(options.friction) !== 'undefined' ? options.friction : -1;
  4004. /**
  4005. * 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.
  4006. * @property {number} restitution
  4007. */
  4008. this.restitution = typeof(options.restitution) !== 'undefined' ? options.restitution : -1;
  4009. }
  4010. Material.idCounter = 0;
  4011. },{}],39:[function(require,module,exports){
  4012. module.exports = JacobianElement;
  4013. var Vec3 = require('./Vec3');
  4014. /**
  4015. * An element containing 6 entries, 3 spatial and 3 rotational degrees of freedom.
  4016. * @class JacobianElement
  4017. * @constructor
  4018. */
  4019. function JacobianElement(){
  4020. /**
  4021. * @property {Vec3} spatial
  4022. */
  4023. this.spatial = new Vec3();
  4024. /**
  4025. * @property {Vec3} rotational
  4026. */
  4027. this.rotational = new Vec3();
  4028. }
  4029. /**
  4030. * Multiply with other JacobianElement
  4031. * @method multiplyElement
  4032. * @param {JacobianElement} element
  4033. * @return {Number}
  4034. */
  4035. JacobianElement.prototype.multiplyElement = function(element){
  4036. return element.spatial.dot(this.spatial) + element.rotational.dot(this.rotational);
  4037. };
  4038. /**
  4039. * Multiply with two vectors
  4040. * @method multiplyVectors
  4041. * @param {Vec3} spatial
  4042. * @param {Vec3} rotational
  4043. * @return {Number}
  4044. */
  4045. JacobianElement.prototype.multiplyVectors = function(spatial,rotational){
  4046. return spatial.dot(this.spatial) + rotational.dot(this.rotational);
  4047. };
  4048. },{"./Vec3":43}],40:[function(require,module,exports){
  4049. module.exports = Mat3;
  4050. var Vec3 = require('./Vec3');
  4051. /**
  4052. * A 3x3 matrix.
  4053. * @class Mat3
  4054. * @constructor
  4055. * @param array elements Array of nine elements. Optional.
  4056. * @author schteppe / http://github.com/schteppe
  4057. */
  4058. function Mat3(elements){
  4059. /**
  4060. * A vector of length 9, containing all matrix elements
  4061. * @property {Array} elements
  4062. */
  4063. if(elements){
  4064. this.elements = elements;
  4065. } else {
  4066. this.elements = [0,0,0,0,0,0,0,0,0];
  4067. }
  4068. }
  4069. /**
  4070. * Sets the matrix to identity
  4071. * @method identity
  4072. * @todo Should perhaps be renamed to setIdentity() to be more clear.
  4073. * @todo Create another function that immediately creates an identity matrix eg. eye()
  4074. */
  4075. Mat3.prototype.identity = function(){
  4076. var e = this.elements;
  4077. e[0] = 1;
  4078. e[1] = 0;
  4079. e[2] = 0;
  4080. e[3] = 0;
  4081. e[4] = 1;
  4082. e[5] = 0;
  4083. e[6] = 0;
  4084. e[7] = 0;
  4085. e[8] = 1;
  4086. };
  4087. /**
  4088. * Set all elements to zero
  4089. * @method setZero
  4090. */
  4091. Mat3.prototype.setZero = function(){
  4092. var e = this.elements;
  4093. e[0] = 0;
  4094. e[1] = 0;
  4095. e[2] = 0;
  4096. e[3] = 0;
  4097. e[4] = 0;
  4098. e[5] = 0;
  4099. e[6] = 0;
  4100. e[7] = 0;
  4101. e[8] = 0;
  4102. };
  4103. /**
  4104. * Sets the matrix diagonal elements from a Vec3
  4105. * @method setTrace
  4106. * @param {Vec3} vec3
  4107. */
  4108. Mat3.prototype.setTrace = function(vec3){
  4109. var e = this.elements;
  4110. e[0] = vec3.x;
  4111. e[4] = vec3.y;
  4112. e[8] = vec3.z;
  4113. };
  4114. /**
  4115. * Gets the matrix diagonal elements
  4116. * @method getTrace
  4117. * @return {Vec3}
  4118. */
  4119. Mat3.prototype.getTrace = function(target){
  4120. var target = target || new Vec3();
  4121. var e = this.elements;
  4122. target.x = e[0];
  4123. target.y = e[4];
  4124. target.z = e[8];
  4125. };
  4126. /**
  4127. * Matrix-Vector multiplication
  4128. * @method vmult
  4129. * @param {Vec3} v The vector to multiply with
  4130. * @param {Vec3} target Optional, target to save the result in.
  4131. */
  4132. Mat3.prototype.vmult = function(v,target){
  4133. target = target || new Vec3();
  4134. var e = this.elements,
  4135. x = v.x,
  4136. y = v.y,
  4137. z = v.z;
  4138. target.x = e[0]*x + e[1]*y + e[2]*z;
  4139. target.y = e[3]*x + e[4]*y + e[5]*z;
  4140. target.z = e[6]*x + e[7]*y + e[8]*z;
  4141. return target;
  4142. };
  4143. /**
  4144. * Matrix-scalar multiplication
  4145. * @method smult
  4146. * @param {Number} s
  4147. */
  4148. Mat3.prototype.smult = function(s){
  4149. for(var i=0; i<this.elements.length; i++){
  4150. this.elements[i] *= s;
  4151. }
  4152. };
  4153. /**
  4154. * Matrix multiplication
  4155. * @method mmult
  4156. * @param {Mat3} m Matrix to multiply with from left side.
  4157. * @return {Mat3} The result.
  4158. */
  4159. Mat3.prototype.mmult = function(m,target){
  4160. var r = target || new Mat3();
  4161. for(var i=0; i<3; i++){
  4162. for(var j=0; j<3; j++){
  4163. var sum = 0.0;
  4164. for(var k=0; k<3; k++){
  4165. sum += m.elements[i+k*3] * this.elements[k+j*3];
  4166. }
  4167. r.elements[i+j*3] = sum;
  4168. }
  4169. }
  4170. return r;
  4171. };
  4172. /**
  4173. * Scale each column of the matrix
  4174. * @method scale
  4175. * @param {Vec3} v
  4176. * @return {Mat3} The result.
  4177. */
  4178. Mat3.prototype.scale = function(v,target){
  4179. target = target || new Mat3();
  4180. var e = this.elements,
  4181. t = target.elements;
  4182. for(var i=0; i!==3; i++){
  4183. t[3*i + 0] = v.x * e[3*i + 0];
  4184. t[3*i + 1] = v.y * e[3*i + 1];
  4185. t[3*i + 2] = v.z * e[3*i + 2];
  4186. }
  4187. return target;
  4188. };
  4189. /**
  4190. * Solve Ax=b
  4191. * @method solve
  4192. * @param {Vec3} b The right hand side
  4193. * @param {Vec3} target Optional. Target vector to save in.
  4194. * @return {Vec3} The solution x
  4195. * @todo should reuse arrays
  4196. */
  4197. Mat3.prototype.solve = function(b,target){
  4198. target = target || new Vec3();
  4199. // Construct equations
  4200. var nr = 3; // num rows
  4201. var nc = 4; // num cols
  4202. var eqns = [];
  4203. for(var i=0; i<nr*nc; i++){
  4204. eqns.push(0);
  4205. }
  4206. var i,j;
  4207. for(i=0; i<3; i++){
  4208. for(j=0; j<3; j++){
  4209. eqns[i+nc*j] = this.elements[i+3*j];
  4210. }
  4211. }
  4212. eqns[3+4*0] = b.x;
  4213. eqns[3+4*1] = b.y;
  4214. eqns[3+4*2] = b.z;
  4215. // Compute right upper triangular version of the matrix - Gauss elimination
  4216. var n = 3, k = n, np;
  4217. var kp = 4; // num rows
  4218. var p, els;
  4219. do {
  4220. i = k - n;
  4221. if (eqns[i+nc*i] === 0) {
  4222. // the pivot is null, swap lines
  4223. for (j = i + 1; j < k; j++) {
  4224. if (eqns[i+nc*j] !== 0) {
  4225. np = kp;
  4226. do { // do ligne( i ) = ligne( i ) + ligne( k )
  4227. p = kp - np;
  4228. eqns[p+nc*i] += eqns[p+nc*j];
  4229. } while (--np);
  4230. break;
  4231. }
  4232. }
  4233. }
  4234. if (eqns[i+nc*i] !== 0) {
  4235. for (j = i + 1; j < k; j++) {
  4236. var multiplier = eqns[i+nc*j] / eqns[i+nc*i];
  4237. np = kp;
  4238. do { // do ligne( k ) = ligne( k ) - multiplier * ligne( i )
  4239. p = kp - np;
  4240. eqns[p+nc*j] = p <= i ? 0 : eqns[p+nc*j] - eqns[p+nc*i] * multiplier ;
  4241. } while (--np);
  4242. }
  4243. }
  4244. } while (--n);
  4245. // Get the solution
  4246. target.z = eqns[2*nc+3] / eqns[2*nc+2];
  4247. target.y = (eqns[1*nc+3] - eqns[1*nc+2]*target.z) / eqns[1*nc+1];
  4248. target.x = (eqns[0*nc+3] - eqns[0*nc+2]*target.z - eqns[0*nc+1]*target.y) / eqns[0*nc+0];
  4249. if(isNaN(target.x) || isNaN(target.y) || isNaN(target.z) || target.x===Infinity || target.y===Infinity || target.z===Infinity){
  4250. throw "Could not solve equation! Got x=["+target.toString()+"], b=["+b.toString()+"], A=["+this.toString()+"]";
  4251. }
  4252. return target;
  4253. };
  4254. /**
  4255. * Get an element in the matrix by index. Index starts at 0, not 1!!!
  4256. * @method e
  4257. * @param {Number} row
  4258. * @param {Number} column
  4259. * @param {Number} value Optional. If provided, the matrix element will be set to this value.
  4260. * @return {Number}
  4261. */
  4262. Mat3.prototype.e = function( row , column ,value){
  4263. if(value===undefined){
  4264. return this.elements[column+3*row];
  4265. } else {
  4266. // Set value
  4267. this.elements[column+3*row] = value;
  4268. }
  4269. };
  4270. /**
  4271. * Copy another matrix into this matrix object.
  4272. * @method copy
  4273. * @param {Mat3} source
  4274. * @return {Mat3} this
  4275. */
  4276. Mat3.prototype.copy = function(source){
  4277. for(var i=0; i < source.elements.length; i++){
  4278. this.elements[i] = source.elements[i];
  4279. }
  4280. return this;
  4281. };
  4282. /**
  4283. * Returns a string representation of the matrix.
  4284. * @method toString
  4285. * @return string
  4286. */
  4287. Mat3.prototype.toString = function(){
  4288. var r = "";
  4289. var sep = ",";
  4290. for(var i=0; i<9; i++){
  4291. r += this.elements[i] + sep;
  4292. }
  4293. return r;
  4294. };
  4295. /**
  4296. * reverse the matrix
  4297. * @method reverse
  4298. * @param {Mat3} target Optional. Target matrix to save in.
  4299. * @return {Mat3} The solution x
  4300. */
  4301. Mat3.prototype.reverse = function(target){
  4302. target = target || new Mat3();
  4303. // Construct equations
  4304. var nr = 3; // num rows
  4305. var nc = 6; // num cols
  4306. var eqns = [];
  4307. for(var i=0; i<nr*nc; i++){
  4308. eqns.push(0);
  4309. }
  4310. var i,j;
  4311. for(i=0; i<3; i++){
  4312. for(j=0; j<3; j++){
  4313. eqns[i+nc*j] = this.elements[i+3*j];
  4314. }
  4315. }
  4316. eqns[3+6*0] = 1;
  4317. eqns[3+6*1] = 0;
  4318. eqns[3+6*2] = 0;
  4319. eqns[4+6*0] = 0;
  4320. eqns[4+6*1] = 1;
  4321. eqns[4+6*2] = 0;
  4322. eqns[5+6*0] = 0;
  4323. eqns[5+6*1] = 0;
  4324. eqns[5+6*2] = 1;
  4325. // Compute right upper triangular version of the matrix - Gauss elimination
  4326. var n = 3, k = n, np;
  4327. var kp = nc; // num rows
  4328. var p;
  4329. do {
  4330. i = k - n;
  4331. if (eqns[i+nc*i] === 0) {
  4332. // the pivot is null, swap lines
  4333. for (j = i + 1; j < k; j++) {
  4334. if (eqns[i+nc*j] !== 0) {
  4335. np = kp;
  4336. do { // do line( i ) = line( i ) + line( k )
  4337. p = kp - np;
  4338. eqns[p+nc*i] += eqns[p+nc*j];
  4339. } while (--np);
  4340. break;
  4341. }
  4342. }
  4343. }
  4344. if (eqns[i+nc*i] !== 0) {
  4345. for (j = i + 1; j < k; j++) {
  4346. var multiplier = eqns[i+nc*j] / eqns[i+nc*i];
  4347. np = kp;
  4348. do { // do line( k ) = line( k ) - multiplier * line( i )
  4349. p = kp - np;
  4350. eqns[p+nc*j] = p <= i ? 0 : eqns[p+nc*j] - eqns[p+nc*i] * multiplier ;
  4351. } while (--np);
  4352. }
  4353. }
  4354. } while (--n);
  4355. // eliminate the upper left triangle of the matrix
  4356. i = 2;
  4357. do {
  4358. j = i-1;
  4359. do {
  4360. var multiplier = eqns[i+nc*j] / eqns[i+nc*i];
  4361. np = nc;
  4362. do {
  4363. p = nc - np;
  4364. eqns[p+nc*j] = eqns[p+nc*j] - eqns[p+nc*i] * multiplier ;
  4365. } while (--np);
  4366. } while (j--);
  4367. } while (--i);
  4368. // operations on the diagonal
  4369. i = 2;
  4370. do {
  4371. var multiplier = 1 / eqns[i+nc*i];
  4372. np = nc;
  4373. do {
  4374. p = nc - np;
  4375. eqns[p+nc*i] = eqns[p+nc*i] * multiplier ;
  4376. } while (--np);
  4377. } while (i--);
  4378. i = 2;
  4379. do {
  4380. j = 2;
  4381. do {
  4382. p = eqns[nr+j+nc*i];
  4383. if( isNaN( p ) || p ===Infinity ){
  4384. throw "Could not reverse! A=["+this.toString()+"]";
  4385. }
  4386. target.e( i , j , p );
  4387. } while (j--);
  4388. } while (i--);
  4389. return target;
  4390. };
  4391. /**
  4392. * Set the matrix from a quaterion
  4393. * @method setRotationFromQuaternion
  4394. * @param {Quaternion} q
  4395. */
  4396. Mat3.prototype.setRotationFromQuaternion = function( q ) {
  4397. var x = q.x, y = q.y, z = q.z, w = q.w,
  4398. x2 = x + x, y2 = y + y, z2 = z + z,
  4399. xx = x * x2, xy = x * y2, xz = x * z2,
  4400. yy = y * y2, yz = y * z2, zz = z * z2,
  4401. wx = w * x2, wy = w * y2, wz = w * z2,
  4402. e = this.elements;
  4403. e[3*0 + 0] = 1 - ( yy + zz );
  4404. e[3*0 + 1] = xy - wz;
  4405. e[3*0 + 2] = xz + wy;
  4406. e[3*1 + 0] = xy + wz;
  4407. e[3*1 + 1] = 1 - ( xx + zz );
  4408. e[3*1 + 2] = yz - wx;
  4409. e[3*2 + 0] = xz - wy;
  4410. e[3*2 + 1] = yz + wx;
  4411. e[3*2 + 2] = 1 - ( xx + yy );
  4412. return this;
  4413. };
  4414. /**
  4415. * Transpose the matrix
  4416. * @method transpose
  4417. * @param {Mat3} target Where to store the result.
  4418. * @return {Mat3} The target Mat3, or a new Mat3 if target was omitted.
  4419. */
  4420. Mat3.prototype.transpose = function( target ) {
  4421. target = target || new Mat3();
  4422. var Mt = target.elements,
  4423. M = this.elements;
  4424. for(var i=0; i!==3; i++){
  4425. for(var j=0; j!==3; j++){
  4426. Mt[3*i + j] = M[3*j + i];
  4427. }
  4428. }
  4429. return target;
  4430. };
  4431. },{"./Vec3":43}],41:[function(require,module,exports){
  4432. module.exports = Quaternion;
  4433. var Vec3 = require('./Vec3');
  4434. /**
  4435. * 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.
  4436. * @class Quaternion
  4437. * @constructor
  4438. * @param {Number} x Multiplier of the imaginary basis vector i.
  4439. * @param {Number} y Multiplier of the imaginary basis vector j.
  4440. * @param {Number} z Multiplier of the imaginary basis vector k.
  4441. * @param {Number} w Multiplier of the real part.
  4442. * @see http://en.wikipedia.org/wiki/Quaternion
  4443. */
  4444. function Quaternion(x,y,z,w){
  4445. /**
  4446. * @property {Number} x
  4447. */
  4448. this.x = x!==undefined ? x : 0;
  4449. /**
  4450. * @property {Number} y
  4451. */
  4452. this.y = y!==undefined ? y : 0;
  4453. /**
  4454. * @property {Number} z
  4455. */
  4456. this.z = z!==undefined ? z : 0;
  4457. /**
  4458. * The multiplier of the real quaternion basis vector.
  4459. * @property {Number} w
  4460. */
  4461. this.w = w!==undefined ? w : 1;
  4462. }
  4463. /**
  4464. * Set the value of the quaternion.
  4465. * @method set
  4466. * @param {Number} x
  4467. * @param {Number} y
  4468. * @param {Number} z
  4469. * @param {Number} w
  4470. */
  4471. Quaternion.prototype.set = function(x,y,z,w){
  4472. this.x = x;
  4473. this.y = y;
  4474. this.z = z;
  4475. this.w = w;
  4476. return this;
  4477. };
  4478. /**
  4479. * Convert to a readable format
  4480. * @method toString
  4481. * @return string
  4482. */
  4483. Quaternion.prototype.toString = function(){
  4484. return this.x+","+this.y+","+this.z+","+this.w;
  4485. };
  4486. /**
  4487. * Convert to an Array
  4488. * @method toArray
  4489. * @return Array
  4490. */
  4491. Quaternion.prototype.toArray = function(){
  4492. return [this.x, this.y, this.z, this.w];
  4493. };
  4494. /**
  4495. * Set the quaternion components given an axis and an angle.
  4496. * @method setFromAxisAngle
  4497. * @param {Vec3} axis
  4498. * @param {Number} angle in radians
  4499. */
  4500. Quaternion.prototype.setFromAxisAngle = function(axis,angle){
  4501. var s = Math.sin(angle*0.5);
  4502. this.x = axis.x * s;
  4503. this.y = axis.y * s;
  4504. this.z = axis.z * s;
  4505. this.w = Math.cos(angle*0.5);
  4506. return this;
  4507. };
  4508. /**
  4509. * Converts the quaternion to axis/angle representation.
  4510. * @method toAxisAngle
  4511. * @param {Vec3} [targetAxis] A vector object to reuse for storing the axis.
  4512. * @return {Array} An array, first elemnt is the axis and the second is the angle in radians.
  4513. */
  4514. Quaternion.prototype.toAxisAngle = function(targetAxis){
  4515. targetAxis = targetAxis || new Vec3();
  4516. this.normalize(); // if w>1 acos and sqrt will produce errors, this cant happen if quaternion is normalised
  4517. var angle = 2 * Math.acos(this.w);
  4518. var s = Math.sqrt(1-this.w*this.w); // assuming quaternion normalised then w is less than 1, so term always positive.
  4519. if (s < 0.001) { // test to avoid divide by zero, s is always positive due to sqrt
  4520. // if s close to zero then direction of axis not important
  4521. targetAxis.x = this.x; // if it is important that axis is normalised then replace with x=1; y=z=0;
  4522. targetAxis.y = this.y;
  4523. targetAxis.z = this.z;
  4524. } else {
  4525. targetAxis.x = this.x / s; // normalise axis
  4526. targetAxis.y = this.y / s;
  4527. targetAxis.z = this.z / s;
  4528. }
  4529. return [targetAxis,angle];
  4530. };
  4531. var sfv_t1 = new Vec3(),
  4532. sfv_t2 = new Vec3();
  4533. /**
  4534. * Set the quaternion value given two vectors. The resulting rotation will be the needed rotation to rotate u to v.
  4535. * @method setFromVectors
  4536. * @param {Vec3} u
  4537. * @param {Vec3} v
  4538. */
  4539. Quaternion.prototype.setFromVectors = function(u,v){
  4540. if(u.isAntiparallelTo(v)){
  4541. var t1 = sfv_t1;
  4542. var t2 = sfv_t2;
  4543. u.tangents(t1,t2);
  4544. this.setFromAxisAngle(t1,Math.PI);
  4545. } else {
  4546. var a = u.cross(v);
  4547. this.x = a.x;
  4548. this.y = a.y;
  4549. this.z = a.z;
  4550. this.w = Math.sqrt(Math.pow(u.norm(),2) * Math.pow(v.norm(),2)) + u.dot(v);
  4551. this.normalize();
  4552. }
  4553. return this;
  4554. };
  4555. /**
  4556. * Quaternion multiplication
  4557. * @method mult
  4558. * @param {Quaternion} q
  4559. * @param {Quaternion} target Optional.
  4560. * @return {Quaternion}
  4561. */
  4562. var Quaternion_mult_va = new Vec3();
  4563. var Quaternion_mult_vb = new Vec3();
  4564. var Quaternion_mult_vaxvb = new Vec3();
  4565. Quaternion.prototype.mult = function(q,target){
  4566. target = target || new Quaternion();
  4567. var ax = this.x, ay = this.y, az = this.z, aw = this.w,
  4568. bx = q.x, by = q.y, bz = q.z, bw = q.w;
  4569. target.x = ax * bw + aw * bx + ay * bz - az * by;
  4570. target.y = ay * bw + aw * by + az * bx - ax * bz;
  4571. target.z = az * bw + aw * bz + ax * by - ay * bx;
  4572. target.w = aw * bw - ax * bx - ay * by - az * bz;
  4573. return target;
  4574. };
  4575. /**
  4576. * Get the inverse quaternion rotation.
  4577. * @method inverse
  4578. * @param {Quaternion} target
  4579. * @return {Quaternion}
  4580. */
  4581. Quaternion.prototype.inverse = function(target){
  4582. var x = this.x, y = this.y, z = this.z, w = this.w;
  4583. target = target || new Quaternion();
  4584. this.conjugate(target);
  4585. var inorm2 = 1/(x*x + y*y + z*z + w*w);
  4586. target.x *= inorm2;
  4587. target.y *= inorm2;
  4588. target.z *= inorm2;
  4589. target.w *= inorm2;
  4590. return target;
  4591. };
  4592. /**
  4593. * Get the quaternion conjugate
  4594. * @method conjugate
  4595. * @param {Quaternion} target
  4596. * @return {Quaternion}
  4597. */
  4598. Quaternion.prototype.conjugate = function(target){
  4599. target = target || new Quaternion();
  4600. target.x = -this.x;
  4601. target.y = -this.y;
  4602. target.z = -this.z;
  4603. target.w = this.w;
  4604. return target;
  4605. };
  4606. /**
  4607. * Normalize the quaternion. Note that this changes the values of the quaternion.
  4608. * @method normalize
  4609. */
  4610. Quaternion.prototype.normalize = function(){
  4611. var l = Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w);
  4612. if ( l === 0 ) {
  4613. this.x = 0;
  4614. this.y = 0;
  4615. this.z = 0;
  4616. this.w = 0;
  4617. } else {
  4618. l = 1 / l;
  4619. this.x *= l;
  4620. this.y *= l;
  4621. this.z *= l;
  4622. this.w *= l;
  4623. }
  4624. return this;
  4625. };
  4626. /**
  4627. * Approximation of quaternion normalization. Works best when quat is already almost-normalized.
  4628. * @method normalizeFast
  4629. * @see http://jsperf.com/fast-quaternion-normalization
  4630. * @author unphased, https://github.com/unphased
  4631. */
  4632. Quaternion.prototype.normalizeFast = function () {
  4633. var f = (3.0-(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w))/2.0;
  4634. if ( f === 0 ) {
  4635. this.x = 0;
  4636. this.y = 0;
  4637. this.z = 0;
  4638. this.w = 0;
  4639. } else {
  4640. this.x *= f;
  4641. this.y *= f;
  4642. this.z *= f;
  4643. this.w *= f;
  4644. }
  4645. return this;
  4646. };
  4647. /**
  4648. * Multiply the quaternion by a vector
  4649. * @method vmult
  4650. * @param {Vec3} v
  4651. * @param {Vec3} target Optional
  4652. * @return {Vec3}
  4653. */
  4654. Quaternion.prototype.vmult = function(v,target){
  4655. target = target || new Vec3();
  4656. var x = v.x,
  4657. y = v.y,
  4658. z = v.z;
  4659. var qx = this.x,
  4660. qy = this.y,
  4661. qz = this.z,
  4662. qw = this.w;
  4663. // q*v
  4664. var ix = qw * x + qy * z - qz * y,
  4665. iy = qw * y + qz * x - qx * z,
  4666. iz = qw * z + qx * y - qy * x,
  4667. iw = -qx * x - qy * y - qz * z;
  4668. target.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
  4669. target.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
  4670. target.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
  4671. return target;
  4672. };
  4673. /**
  4674. * Copies value of source to this quaternion.
  4675. * @method copy
  4676. * @param {Quaternion} source
  4677. * @return {Quaternion} this
  4678. */
  4679. Quaternion.prototype.copy = function(source){
  4680. this.x = source.x;
  4681. this.y = source.y;
  4682. this.z = source.z;
  4683. this.w = source.w;
  4684. return this;
  4685. };
  4686. /**
  4687. * Convert the quaternion to euler angle representation. Order: YZX, as this page describes: http://www.euclideanspace.com/maths/standards/index.htm
  4688. * @method toEuler
  4689. * @param {Vec3} target
  4690. * @param string order Three-character string e.g. "YZX", which also is default.
  4691. */
  4692. Quaternion.prototype.toEuler = function(target,order){
  4693. order = order || "YZX";
  4694. var heading, attitude, bank;
  4695. var x = this.x, y = this.y, z = this.z, w = this.w;
  4696. switch(order){
  4697. case "YZX":
  4698. var test = x*y + z*w;
  4699. if (test > 0.499) { // singularity at north pole
  4700. heading = 2 * Math.atan2(x,w);
  4701. attitude = Math.PI/2;
  4702. bank = 0;
  4703. }
  4704. if (test < -0.499) { // singularity at south pole
  4705. heading = -2 * Math.atan2(x,w);
  4706. attitude = - Math.PI/2;
  4707. bank = 0;
  4708. }
  4709. if(isNaN(heading)){
  4710. var sqx = x*x;
  4711. var sqy = y*y;
  4712. var sqz = z*z;
  4713. heading = Math.atan2(2*y*w - 2*x*z , 1 - 2*sqy - 2*sqz); // Heading
  4714. attitude = Math.asin(2*test); // attitude
  4715. bank = Math.atan2(2*x*w - 2*y*z , 1 - 2*sqx - 2*sqz); // bank
  4716. }
  4717. break;
  4718. default:
  4719. throw new Error("Euler order "+order+" not supported yet.");
  4720. }
  4721. target.y = heading;
  4722. target.z = attitude;
  4723. target.x = bank;
  4724. };
  4725. /**
  4726. * See http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m
  4727. * @method setFromEuler
  4728. * @param {Number} x
  4729. * @param {Number} y
  4730. * @param {Number} z
  4731. * @param {String} order The order to apply angles: 'XYZ' or 'YXZ' or any other combination
  4732. */
  4733. Quaternion.prototype.setFromEuler = function ( x, y, z, order ) {
  4734. order = order || "XYZ";
  4735. var c1 = Math.cos( x / 2 );
  4736. var c2 = Math.cos( y / 2 );
  4737. var c3 = Math.cos( z / 2 );
  4738. var s1 = Math.sin( x / 2 );
  4739. var s2 = Math.sin( y / 2 );
  4740. var s3 = Math.sin( z / 2 );
  4741. if ( order === 'XYZ' ) {
  4742. this.x = s1 * c2 * c3 + c1 * s2 * s3;
  4743. this.y = c1 * s2 * c3 - s1 * c2 * s3;
  4744. this.z = c1 * c2 * s3 + s1 * s2 * c3;
  4745. this.w = c1 * c2 * c3 - s1 * s2 * s3;
  4746. } else if ( order === 'YXZ' ) {
  4747. this.x = s1 * c2 * c3 + c1 * s2 * s3;
  4748. this.y = c1 * s2 * c3 - s1 * c2 * s3;
  4749. this.z = c1 * c2 * s3 - s1 * s2 * c3;
  4750. this.w = c1 * c2 * c3 + s1 * s2 * s3;
  4751. } else if ( order === 'ZXY' ) {
  4752. this.x = s1 * c2 * c3 - c1 * s2 * s3;
  4753. this.y = c1 * s2 * c3 + s1 * c2 * s3;
  4754. this.z = c1 * c2 * s3 + s1 * s2 * c3;
  4755. this.w = c1 * c2 * c3 - s1 * s2 * s3;
  4756. } else if ( order === 'ZYX' ) {
  4757. this.x = s1 * c2 * c3 - c1 * s2 * s3;
  4758. this.y = c1 * s2 * c3 + s1 * c2 * s3;
  4759. this.z = c1 * c2 * s3 - s1 * s2 * c3;
  4760. this.w = c1 * c2 * c3 + s1 * s2 * s3;
  4761. } else if ( order === 'YZX' ) {
  4762. this.x = s1 * c2 * c3 + c1 * s2 * s3;
  4763. this.y = c1 * s2 * c3 + s1 * c2 * s3;
  4764. this.z = c1 * c2 * s3 - s1 * s2 * c3;
  4765. this.w = c1 * c2 * c3 - s1 * s2 * s3;
  4766. } else if ( order === 'XZY' ) {
  4767. this.x = s1 * c2 * c3 - c1 * s2 * s3;
  4768. this.y = c1 * s2 * c3 - s1 * c2 * s3;
  4769. this.z = c1 * c2 * s3 + s1 * s2 * c3;
  4770. this.w = c1 * c2 * c3 + s1 * s2 * s3;
  4771. }
  4772. return this;
  4773. };
  4774. /**
  4775. * @method clone
  4776. * @return {Quaternion}
  4777. */
  4778. Quaternion.prototype.clone = function(){
  4779. return new Quaternion(this.x, this.y, this.z, this.w);
  4780. };
  4781. /**
  4782. * Performs a spherical linear interpolation between two quat
  4783. *
  4784. * @method slerp
  4785. * @param {Quaternion} toQuat second operand
  4786. * @param {Number} t interpolation amount between the self quaternion and toQuat
  4787. * @param {Quaternion} [target] A quaternion to store the result in. If not provided, a new one will be created.
  4788. * @returns {Quaternion} The "target" object
  4789. */
  4790. Quaternion.prototype.slerp = function (toQuat, t, target) {
  4791. target = target || new Quaternion();
  4792. var ax = this.x,
  4793. ay = this.y,
  4794. az = this.z,
  4795. aw = this.w,
  4796. bx = toQuat.x,
  4797. by = toQuat.y,
  4798. bz = toQuat.z,
  4799. bw = toQuat.w;
  4800. var omega, cosom, sinom, scale0, scale1;
  4801. // calc cosine
  4802. cosom = ax * bx + ay * by + az * bz + aw * bw;
  4803. // adjust signs (if necessary)
  4804. if ( cosom < 0.0 ) {
  4805. cosom = -cosom;
  4806. bx = - bx;
  4807. by = - by;
  4808. bz = - bz;
  4809. bw = - bw;
  4810. }
  4811. // calculate coefficients
  4812. if ( (1.0 - cosom) > 0.000001 ) {
  4813. // standard case (slerp)
  4814. omega = Math.acos(cosom);
  4815. sinom = Math.sin(omega);
  4816. scale0 = Math.sin((1.0 - t) * omega) / sinom;
  4817. scale1 = Math.sin(t * omega) / sinom;
  4818. } else {
  4819. // "from" and "to" quaternions are very close
  4820. // ... so we can do a linear interpolation
  4821. scale0 = 1.0 - t;
  4822. scale1 = t;
  4823. }
  4824. // calculate final values
  4825. target.x = scale0 * ax + scale1 * bx;
  4826. target.y = scale0 * ay + scale1 * by;
  4827. target.z = scale0 * az + scale1 * bz;
  4828. target.w = scale0 * aw + scale1 * bw;
  4829. return target;
  4830. };
  4831. /**
  4832. * Rotate an absolute orientation quaternion given an angular velocity and a time step.
  4833. * @param {Vec3} angularVelocity
  4834. * @param {number} dt
  4835. * @param {Vec3} angularFactor
  4836. * @param {Quaternion} target
  4837. * @return {Quaternion} The "target" object
  4838. */
  4839. Quaternion.prototype.integrate = function(angularVelocity, dt, angularFactor, target){
  4840. target = target || new Quaternion();
  4841. var ax = angularVelocity.x * angularFactor.x,
  4842. ay = angularVelocity.y * angularFactor.y,
  4843. az = angularVelocity.z * angularFactor.z,
  4844. bx = this.x,
  4845. by = this.y,
  4846. bz = this.z,
  4847. bw = this.w;
  4848. var half_dt = dt * 0.5;
  4849. target.x += half_dt * (ax * bw + ay * bz - az * by);
  4850. target.y += half_dt * (ay * bw + az * bx - ax * bz);
  4851. target.z += half_dt * (az * bw + ax * by - ay * bx);
  4852. target.w += half_dt * (- ax * bx - ay * by - az * bz);
  4853. return target;
  4854. };
  4855. },{"./Vec3":43}],42:[function(require,module,exports){
  4856. var Vec3 = require('./Vec3');
  4857. var Quaternion = require('./Quaternion');
  4858. module.exports = Transform;
  4859. /**
  4860. * @class Transform
  4861. * @constructor
  4862. */
  4863. function Transform(options) {
  4864. options = options || {};
  4865. /**
  4866. * @property {Vec3} position
  4867. */
  4868. this.position = new Vec3();
  4869. if(options.position){
  4870. this.position.copy(options.position);
  4871. }
  4872. /**
  4873. * @property {Quaternion} quaternion
  4874. */
  4875. this.quaternion = new Quaternion();
  4876. if(options.quaternion){
  4877. this.quaternion.copy(options.quaternion);
  4878. }
  4879. }
  4880. var tmpQuat = new Quaternion();
  4881. /**
  4882. * @static
  4883. * @method pointToLocaFrame
  4884. * @param {Vec3} position
  4885. * @param {Quaternion} quaternion
  4886. * @param {Vec3} worldPoint
  4887. * @param {Vec3} result
  4888. */
  4889. Transform.pointToLocalFrame = function(position, quaternion, worldPoint, result){
  4890. var result = result || new Vec3();
  4891. worldPoint.vsub(position, result);
  4892. quaternion.conjugate(tmpQuat);
  4893. tmpQuat.vmult(result, result);
  4894. return result;
  4895. };
  4896. /**
  4897. * Get a global point in local transform coordinates.
  4898. * @method pointToLocal
  4899. * @param {Vec3} point
  4900. * @param {Vec3} result
  4901. * @return {Vec3} The "result" vector object
  4902. */
  4903. Transform.prototype.pointToLocal = function(worldPoint, result){
  4904. return Transform.pointToLocalFrame(this.position, this.quaternion, worldPoint, result);
  4905. };
  4906. /**
  4907. * @static
  4908. * @method pointToWorldFrame
  4909. * @param {Vec3} position
  4910. * @param {Vec3} quaternion
  4911. * @param {Vec3} localPoint
  4912. * @param {Vec3} result
  4913. */
  4914. Transform.pointToWorldFrame = function(position, quaternion, localPoint, result){
  4915. var result = result || new Vec3();
  4916. quaternion.vmult(localPoint, result);
  4917. result.vadd(position, result);
  4918. return result;
  4919. };
  4920. /**
  4921. * Get a local point in global transform coordinates.
  4922. * @method pointToWorld
  4923. * @param {Vec3} point
  4924. * @param {Vec3} result
  4925. * @return {Vec3} The "result" vector object
  4926. */
  4927. Transform.prototype.pointToWorld = function(localPoint, result){
  4928. return Transform.pointToWorldFrame(this.position, this.quaternion, localPoint, result);
  4929. };
  4930. Transform.prototype.vectorToWorldFrame = function(localVector, result){
  4931. var result = result || new Vec3();
  4932. this.quaternion.vmult(localVector, result);
  4933. return result;
  4934. };
  4935. Transform.vectorToWorldFrame = function(quaternion, localVector, result){
  4936. quaternion.vmult(localVector, result);
  4937. return result;
  4938. };
  4939. Transform.vectorToLocalFrame = function(position, quaternion, worldVector, result){
  4940. var result = result || new Vec3();
  4941. quaternion.w *= -1;
  4942. quaternion.vmult(worldVector, result);
  4943. quaternion.w *= -1;
  4944. return result;
  4945. };
  4946. },{"./Quaternion":41,"./Vec3":43}],43:[function(require,module,exports){
  4947. module.exports = Vec3;
  4948. var Mat3 = require('./Mat3');
  4949. /**
  4950. * 3-dimensional vector
  4951. * @class Vec3
  4952. * @constructor
  4953. * @param {Number} x
  4954. * @param {Number} y
  4955. * @param {Number} z
  4956. * @author schteppe
  4957. * @example
  4958. * var v = new Vec3(1, 2, 3);
  4959. * console.log('x=' + v.x); // x=1
  4960. */
  4961. function Vec3(x,y,z){
  4962. /**
  4963. * @property x
  4964. * @type {Number}
  4965. */
  4966. this.x = x||0.0;
  4967. /**
  4968. * @property y
  4969. * @type {Number}
  4970. */
  4971. this.y = y||0.0;
  4972. /**
  4973. * @property z
  4974. * @type {Number}
  4975. */
  4976. this.z = z||0.0;
  4977. }
  4978. /**
  4979. * @static
  4980. * @property {Vec3} ZERO
  4981. */
  4982. Vec3.ZERO = new Vec3(0, 0, 0);
  4983. /**
  4984. * @static
  4985. * @property {Vec3} UNIT_X
  4986. */
  4987. Vec3.UNIT_X = new Vec3(1, 0, 0);
  4988. /**
  4989. * @static
  4990. * @property {Vec3} UNIT_Y
  4991. */
  4992. Vec3.UNIT_Y = new Vec3(0, 1, 0);
  4993. /**
  4994. * @static
  4995. * @property {Vec3} UNIT_Z
  4996. */
  4997. Vec3.UNIT_Z = new Vec3(0, 0, 1);
  4998. /**
  4999. * Vector cross product
  5000. * @method cross
  5001. * @param {Vec3} v
  5002. * @param {Vec3} target Optional. Target to save in.
  5003. * @return {Vec3}
  5004. */
  5005. Vec3.prototype.cross = function(v,target){
  5006. var vx=v.x, vy=v.y, vz=v.z, x=this.x, y=this.y, z=this.z;
  5007. target = target || new Vec3();
  5008. target.x = (y * vz) - (z * vy);
  5009. target.y = (z * vx) - (x * vz);
  5010. target.z = (x * vy) - (y * vx);
  5011. return target;
  5012. };
  5013. /**
  5014. * Set the vectors' 3 elements
  5015. * @method set
  5016. * @param {Number} x
  5017. * @param {Number} y
  5018. * @param {Number} z
  5019. * @return Vec3
  5020. */
  5021. Vec3.prototype.set = function(x,y,z){
  5022. this.x = x;
  5023. this.y = y;
  5024. this.z = z;
  5025. return this;
  5026. };
  5027. /**
  5028. * Set all components of the vector to zero.
  5029. * @method setZero
  5030. */
  5031. Vec3.prototype.setZero = function(){
  5032. this.x = this.y = this.z = 0;
  5033. };
  5034. /**
  5035. * Vector addition
  5036. * @method vadd
  5037. * @param {Vec3} v
  5038. * @param {Vec3} target Optional.
  5039. * @return {Vec3}
  5040. */
  5041. Vec3.prototype.vadd = function(v,target){
  5042. if(target){
  5043. target.x = v.x + this.x;
  5044. target.y = v.y + this.y;
  5045. target.z = v.z + this.z;
  5046. } else {
  5047. return new Vec3(this.x + v.x,
  5048. this.y + v.y,
  5049. this.z + v.z);
  5050. }
  5051. };
  5052. /**
  5053. * Vector subtraction
  5054. * @method vsub
  5055. * @param {Vec3} v
  5056. * @param {Vec3} target Optional. Target to save in.
  5057. * @return {Vec3}
  5058. */
  5059. Vec3.prototype.vsub = function(v,target){
  5060. if(target){
  5061. target.x = this.x - v.x;
  5062. target.y = this.y - v.y;
  5063. target.z = this.z - v.z;
  5064. } else {
  5065. return new Vec3(this.x-v.x,
  5066. this.y-v.y,
  5067. this.z-v.z);
  5068. }
  5069. };
  5070. /**
  5071. * Get the cross product matrix a_cross from a vector, such that a x b = a_cross * b = c
  5072. * @method crossmat
  5073. * @see http://www8.cs.umu.se/kurser/TDBD24/VT06/lectures/Lecture6.pdf
  5074. * @return {Mat3}
  5075. */
  5076. Vec3.prototype.crossmat = function(){
  5077. return new Mat3([ 0, -this.z, this.y,
  5078. this.z, 0, -this.x,
  5079. -this.y, this.x, 0]);
  5080. };
  5081. /**
  5082. * Normalize the vector. Note that this changes the values in the vector.
  5083. * @method normalize
  5084. * @return {Number} Returns the norm of the vector
  5085. */
  5086. Vec3.prototype.normalize = function(){
  5087. var x=this.x, y=this.y, z=this.z;
  5088. var n = Math.sqrt(x*x + y*y + z*z);
  5089. if(n>0.0){
  5090. var invN = 1/n;
  5091. this.x *= invN;
  5092. this.y *= invN;
  5093. this.z *= invN;
  5094. } else {
  5095. // Make something up
  5096. this.x = 0;
  5097. this.y = 0;
  5098. this.z = 0;
  5099. }
  5100. return n;
  5101. };
  5102. /**
  5103. * Get the version of this vector that is of length 1.
  5104. * @method unit
  5105. * @param {Vec3} target Optional target to save in
  5106. * @return {Vec3} Returns the unit vector
  5107. */
  5108. Vec3.prototype.unit = function(target){
  5109. target = target || new Vec3();
  5110. var x=this.x, y=this.y, z=this.z;
  5111. var ninv = Math.sqrt(x*x + y*y + z*z);
  5112. if(ninv>0.0){
  5113. ninv = 1.0/ninv;
  5114. target.x = x * ninv;
  5115. target.y = y * ninv;
  5116. target.z = z * ninv;
  5117. } else {
  5118. target.x = 1;
  5119. target.y = 0;
  5120. target.z = 0;
  5121. }
  5122. return target;
  5123. };
  5124. /**
  5125. * Get the length of the vector
  5126. * @method norm
  5127. * @return {Number}
  5128. * @deprecated Use .length() instead
  5129. */
  5130. Vec3.prototype.norm = function(){
  5131. var x=this.x, y=this.y, z=this.z;
  5132. return Math.sqrt(x*x + y*y + z*z);
  5133. };
  5134. /**
  5135. * Get the length of the vector
  5136. * @method length
  5137. * @return {Number}
  5138. */
  5139. Vec3.prototype.length = Vec3.prototype.norm;
  5140. /**
  5141. * Get the squared length of the vector
  5142. * @method norm2
  5143. * @return {Number}
  5144. * @deprecated Use .lengthSquared() instead.
  5145. */
  5146. Vec3.prototype.norm2 = function(){
  5147. return this.dot(this);
  5148. };
  5149. /**
  5150. * Get the squared length of the vector.
  5151. * @method lengthSquared
  5152. * @return {Number}
  5153. */
  5154. Vec3.prototype.lengthSquared = Vec3.prototype.norm2;
  5155. /**
  5156. * Get distance from this point to another point
  5157. * @method distanceTo
  5158. * @param {Vec3} p
  5159. * @return {Number}
  5160. */
  5161. Vec3.prototype.distanceTo = function(p){
  5162. var x=this.x, y=this.y, z=this.z;
  5163. var px=p.x, py=p.y, pz=p.z;
  5164. return Math.sqrt((px-x)*(px-x)+
  5165. (py-y)*(py-y)+
  5166. (pz-z)*(pz-z));
  5167. };
  5168. /**
  5169. * Get squared distance from this point to another point
  5170. * @method distanceSquared
  5171. * @param {Vec3} p
  5172. * @return {Number}
  5173. */
  5174. Vec3.prototype.distanceSquared = function(p){
  5175. var x=this.x, y=this.y, z=this.z;
  5176. var px=p.x, py=p.y, pz=p.z;
  5177. return (px-x)*(px-x) + (py-y)*(py-y) + (pz-z)*(pz-z);
  5178. };
  5179. /**
  5180. * Multiply all the components of the vector with a scalar.
  5181. * @deprecated Use .scale instead
  5182. * @method mult
  5183. * @param {Number} scalar
  5184. * @param {Vec3} target The vector to save the result in.
  5185. * @return {Vec3}
  5186. * @deprecated Use .scale() instead
  5187. */
  5188. Vec3.prototype.mult = function(scalar,target){
  5189. target = target || new Vec3();
  5190. var x = this.x,
  5191. y = this.y,
  5192. z = this.z;
  5193. target.x = scalar * x;
  5194. target.y = scalar * y;
  5195. target.z = scalar * z;
  5196. return target;
  5197. };
  5198. /**
  5199. * Multiply the vector with an other vector, component-wise.
  5200. * @method mult
  5201. * @param {Number} vector
  5202. * @param {Vec3} target The vector to save the result in.
  5203. * @return {Vec3}
  5204. */
  5205. Vec3.prototype.vmul = function(vector, target){
  5206. target = target || new Vec3();
  5207. target.x = vector.x * this.x;
  5208. target.y = vector.y * this.y;
  5209. target.z = vector.z * this.z;
  5210. return target;
  5211. };
  5212. /**
  5213. * Multiply the vector with a scalar.
  5214. * @method scale
  5215. * @param {Number} scalar
  5216. * @param {Vec3} target
  5217. * @return {Vec3}
  5218. */
  5219. Vec3.prototype.scale = Vec3.prototype.mult;
  5220. /**
  5221. * Scale a vector and add it to this vector. Save the result in "target". (target = this + vector * scalar)
  5222. * @method addScaledVector
  5223. * @param {Number} scalar
  5224. * @param {Vec3} vector
  5225. * @param {Vec3} target The vector to save the result in.
  5226. * @return {Vec3}
  5227. */
  5228. Vec3.prototype.addScaledVector = function(scalar, vector, target){
  5229. target = target || new Vec3();
  5230. target.x = this.x + scalar * vector.x;
  5231. target.y = this.y + scalar * vector.y;
  5232. target.z = this.z + scalar * vector.z;
  5233. return target;
  5234. };
  5235. /**
  5236. * Calculate dot product
  5237. * @method dot
  5238. * @param {Vec3} v
  5239. * @return {Number}
  5240. */
  5241. Vec3.prototype.dot = function(v){
  5242. return this.x * v.x + this.y * v.y + this.z * v.z;
  5243. };
  5244. /**
  5245. * @method isZero
  5246. * @return bool
  5247. */
  5248. Vec3.prototype.isZero = function(){
  5249. return this.x===0 && this.y===0 && this.z===0;
  5250. };
  5251. /**
  5252. * Make the vector point in the opposite direction.
  5253. * @method negate
  5254. * @param {Vec3} target Optional target to save in
  5255. * @return {Vec3}
  5256. */
  5257. Vec3.prototype.negate = function(target){
  5258. target = target || new Vec3();
  5259. target.x = -this.x;
  5260. target.y = -this.y;
  5261. target.z = -this.z;
  5262. return target;
  5263. };
  5264. /**
  5265. * Compute two artificial tangents to the vector
  5266. * @method tangents
  5267. * @param {Vec3} t1 Vector object to save the first tangent in
  5268. * @param {Vec3} t2 Vector object to save the second tangent in
  5269. */
  5270. var Vec3_tangents_n = new Vec3();
  5271. var Vec3_tangents_randVec = new Vec3();
  5272. Vec3.prototype.tangents = function(t1,t2){
  5273. var norm = this.norm();
  5274. if(norm>0.0){
  5275. var n = Vec3_tangents_n;
  5276. var inorm = 1/norm;
  5277. n.set(this.x*inorm,this.y*inorm,this.z*inorm);
  5278. var randVec = Vec3_tangents_randVec;
  5279. if(Math.abs(n.x) < 0.9){
  5280. randVec.set(1,0,0);
  5281. n.cross(randVec,t1);
  5282. } else {
  5283. randVec.set(0,1,0);
  5284. n.cross(randVec,t1);
  5285. }
  5286. n.cross(t1,t2);
  5287. } else {
  5288. // The normal length is zero, make something up
  5289. t1.set(1, 0, 0);
  5290. t2.set(0, 1, 0);
  5291. }
  5292. };
  5293. /**
  5294. * Converts to a more readable format
  5295. * @method toString
  5296. * @return string
  5297. */
  5298. Vec3.prototype.toString = function(){
  5299. return this.x+","+this.y+","+this.z;
  5300. };
  5301. /**
  5302. * Converts to an array
  5303. * @method toArray
  5304. * @return Array
  5305. */
  5306. Vec3.prototype.toArray = function(){
  5307. return [this.x, this.y, this.z];
  5308. };
  5309. /**
  5310. * Copies value of source to this vector.
  5311. * @method copy
  5312. * @param {Vec3} source
  5313. * @return {Vec3} this
  5314. */
  5315. Vec3.prototype.copy = function(source){
  5316. this.x = source.x;
  5317. this.y = source.y;
  5318. this.z = source.z;
  5319. return this;
  5320. };
  5321. /**
  5322. * Do a linear interpolation between two vectors
  5323. * @method lerp
  5324. * @param {Vec3} v
  5325. * @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.
  5326. * @param {Vec3} target
  5327. */
  5328. Vec3.prototype.lerp = function(v,t,target){
  5329. var x=this.x, y=this.y, z=this.z;
  5330. target.x = x + (v.x-x)*t;
  5331. target.y = y + (v.y-y)*t;
  5332. target.z = z + (v.z-z)*t;
  5333. };
  5334. /**
  5335. * Check if a vector equals is almost equal to another one.
  5336. * @method almostEquals
  5337. * @param {Vec3} v
  5338. * @param {Number} precision
  5339. * @return bool
  5340. */
  5341. Vec3.prototype.almostEquals = function(v,precision){
  5342. if(precision===undefined){
  5343. precision = 1e-6;
  5344. }
  5345. if( Math.abs(this.x-v.x)>precision ||
  5346. Math.abs(this.y-v.y)>precision ||
  5347. Math.abs(this.z-v.z)>precision){
  5348. return false;
  5349. }
  5350. return true;
  5351. };
  5352. /**
  5353. * Check if a vector is almost zero
  5354. * @method almostZero
  5355. * @param {Number} precision
  5356. */
  5357. Vec3.prototype.almostZero = function(precision){
  5358. if(precision===undefined){
  5359. precision = 1e-6;
  5360. }
  5361. if( Math.abs(this.x)>precision ||
  5362. Math.abs(this.y)>precision ||
  5363. Math.abs(this.z)>precision){
  5364. return false;
  5365. }
  5366. return true;
  5367. };
  5368. var antip_neg = new Vec3();
  5369. /**
  5370. * Check if the vector is anti-parallel to another vector.
  5371. * @method isAntiparallelTo
  5372. * @param {Vec3} v
  5373. * @param {Number} precision Set to zero for exact comparisons
  5374. * @return {Boolean}
  5375. */
  5376. Vec3.prototype.isAntiparallelTo = function(v,precision){
  5377. this.negate(antip_neg);
  5378. return antip_neg.almostEquals(v,precision);
  5379. };
  5380. /**
  5381. * Clone the vector
  5382. * @method clone
  5383. * @return {Vec3}
  5384. */
  5385. Vec3.prototype.clone = function(){
  5386. return new Vec3(this.x, this.y, this.z);
  5387. };
  5388. },{"./Mat3":40}],44:[function(require,module,exports){
  5389. module.exports = Body;
  5390. var EventTarget = require('../utils/EventTarget');
  5391. var Shape = require('../shapes/Shape');
  5392. var Vec3 = require('../math/Vec3');
  5393. var Mat3 = require('../math/Mat3');
  5394. var Quaternion = require('../math/Quaternion');
  5395. var Material = require('../material/Material');
  5396. var AABB = require('../collision/AABB');
  5397. var Box = require('../shapes/Box');
  5398. /**
  5399. * Base class for all body types.
  5400. * @class Body
  5401. * @constructor
  5402. * @extends EventTarget
  5403. * @param {object} [options]
  5404. * @param {Vec3} [options.position]
  5405. * @param {Vec3} [options.velocity]
  5406. * @param {Vec3} [options.angularVelocity]
  5407. * @param {Quaternion} [options.quaternion]
  5408. * @param {number} [options.mass]
  5409. * @param {Material} [options.material]
  5410. * @param {number} [options.type]
  5411. * @param {number} [options.linearDamping=0.01]
  5412. * @param {number} [options.angularDamping=0.01]
  5413. * @param {boolean} [options.allowSleep=true]
  5414. * @param {number} [options.sleepSpeedLimit=0.1]
  5415. * @param {number} [options.sleepTimeLimit=1]
  5416. * @param {number} [options.collisionFilterGroup=1]
  5417. * @param {number} [options.collisionFilterMask=1]
  5418. * @param {boolean} [options.fixedRotation=false]
  5419. * @param {Vec3} [options.linearFactor]
  5420. * @param {Vec3} [options.angularFactor]
  5421. * @param {Shape} [options.shape]
  5422. * @example
  5423. * var body = new Body({
  5424. * mass: 1
  5425. * });
  5426. * var shape = new Sphere(1);
  5427. * body.addShape(shape);
  5428. * world.addBody(body);
  5429. */
  5430. function Body(options){
  5431. options = options || {};
  5432. EventTarget.apply(this);
  5433. this.id = Body.idCounter++;
  5434. /**
  5435. * Reference to the world the body is living in
  5436. * @property world
  5437. * @type {World}
  5438. */
  5439. this.world = null;
  5440. /**
  5441. * 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.
  5442. * @property preStep
  5443. * @type {Function}
  5444. * @deprecated Use World events instead
  5445. */
  5446. this.preStep = null;
  5447. /**
  5448. * Callback function that is used AFTER stepping the system. Inside the function, "this" will refer to this Body object.
  5449. * @property postStep
  5450. * @type {Function}
  5451. * @deprecated Use World events instead
  5452. */
  5453. this.postStep = null;
  5454. this.vlambda = new Vec3();
  5455. /**
  5456. * @property {Number} collisionFilterGroup
  5457. */
  5458. this.collisionFilterGroup = typeof(options.collisionFilterGroup) === 'number' ? options.collisionFilterGroup : 1;
  5459. /**
  5460. * @property {Number} collisionFilterMask
  5461. */
  5462. this.collisionFilterMask = typeof(options.collisionFilterMask) === 'number' ? options.collisionFilterMask : 1;
  5463. /**
  5464. * Whether to produce contact forces when in contact with other bodies. Note that contacts will be generated, but they will be disabled.
  5465. * @property {Number} collisionResponse
  5466. */
  5467. this.collisionResponse = true;
  5468. /**
  5469. * @property position
  5470. * @type {Vec3}
  5471. */
  5472. this.position = new Vec3();
  5473. /**
  5474. * @property {Vec3} previousPosition
  5475. */
  5476. this.previousPosition = new Vec3();
  5477. /**
  5478. * Interpolated position of the body.
  5479. * @property {Vec3} interpolatedPosition
  5480. */
  5481. this.interpolatedPosition = new Vec3();
  5482. /**
  5483. * Initial position of the body
  5484. * @property initPosition
  5485. * @type {Vec3}
  5486. */
  5487. this.initPosition = new Vec3();
  5488. if(options.position){
  5489. this.position.copy(options.position);
  5490. this.previousPosition.copy(options.position);
  5491. this.interpolatedPosition.copy(options.position);
  5492. this.initPosition.copy(options.position);
  5493. }
  5494. /**
  5495. * @property velocity
  5496. * @type {Vec3}
  5497. */
  5498. this.velocity = new Vec3();
  5499. if(options.velocity){
  5500. this.velocity.copy(options.velocity);
  5501. }
  5502. /**
  5503. * @property initVelocity
  5504. * @type {Vec3}
  5505. */
  5506. this.initVelocity = new Vec3();
  5507. /**
  5508. * Linear force on the body
  5509. * @property force
  5510. * @type {Vec3}
  5511. */
  5512. this.force = new Vec3();
  5513. var mass = typeof(options.mass) === 'number' ? options.mass : 0;
  5514. /**
  5515. * @property mass
  5516. * @type {Number}
  5517. * @default 0
  5518. */
  5519. this.mass = mass;
  5520. /**
  5521. * @property invMass
  5522. * @type {Number}
  5523. */
  5524. this.invMass = mass > 0 ? 1.0 / mass : 0;
  5525. /**
  5526. * @property material
  5527. * @type {Material}
  5528. */
  5529. this.material = options.material || null;
  5530. /**
  5531. * @property linearDamping
  5532. * @type {Number}
  5533. */
  5534. this.linearDamping = typeof(options.linearDamping) === 'number' ? options.linearDamping : 0.01;
  5535. /**
  5536. * One of: Body.DYNAMIC, Body.STATIC and Body.KINEMATIC.
  5537. * @property type
  5538. * @type {Number}
  5539. */
  5540. this.type = (mass <= 0.0 ? Body.STATIC : Body.DYNAMIC);
  5541. if(typeof(options.type) === typeof(Body.STATIC)){
  5542. this.type = options.type;
  5543. }
  5544. /**
  5545. * If true, the body will automatically fall to sleep.
  5546. * @property allowSleep
  5547. * @type {Boolean}
  5548. * @default true
  5549. */
  5550. this.allowSleep = typeof(options.allowSleep) !== 'undefined' ? options.allowSleep : true;
  5551. /**
  5552. * Current sleep state.
  5553. * @property sleepState
  5554. * @type {Number}
  5555. */
  5556. this.sleepState = 0;
  5557. /**
  5558. * If the speed (the norm of the velocity) is smaller than this value, the body is considered sleepy.
  5559. * @property sleepSpeedLimit
  5560. * @type {Number}
  5561. * @default 0.1
  5562. */
  5563. this.sleepSpeedLimit = typeof(options.sleepSpeedLimit) !== 'undefined' ? options.sleepSpeedLimit : 0.1;
  5564. /**
  5565. * If the body has been sleepy for this sleepTimeLimit seconds, it is considered sleeping.
  5566. * @property sleepTimeLimit
  5567. * @type {Number}
  5568. * @default 1
  5569. */
  5570. this.sleepTimeLimit = typeof(options.sleepTimeLimit) !== 'undefined' ? options.sleepTimeLimit : 1;
  5571. this.timeLastSleepy = 0;
  5572. this._wakeUpAfterNarrowphase = false;
  5573. /**
  5574. * Rotational force on the body, around center of mass
  5575. * @property {Vec3} torque
  5576. */
  5577. this.torque = new Vec3();
  5578. /**
  5579. * Orientation of the body
  5580. * @property quaternion
  5581. * @type {Quaternion}
  5582. */
  5583. this.quaternion = new Quaternion();
  5584. /**
  5585. * @property initQuaternion
  5586. * @type {Quaternion}
  5587. */
  5588. this.initQuaternion = new Quaternion();
  5589. /**
  5590. * @property {Quaternion} previousQuaternion
  5591. */
  5592. this.previousQuaternion = new Quaternion();
  5593. /**
  5594. * Interpolated orientation of the body.
  5595. * @property {Quaternion} interpolatedQuaternion
  5596. */
  5597. this.interpolatedQuaternion = new Quaternion();
  5598. if(options.quaternion){
  5599. this.quaternion.copy(options.quaternion);
  5600. this.initQuaternion.copy(options.quaternion);
  5601. this.previousQuaternion.copy(options.quaternion);
  5602. this.interpolatedQuaternion.copy(options.quaternion);
  5603. }
  5604. /**
  5605. * @property angularVelocity
  5606. * @type {Vec3}
  5607. */
  5608. this.angularVelocity = new Vec3();
  5609. if(options.angularVelocity){
  5610. this.angularVelocity.copy(options.angularVelocity);
  5611. }
  5612. /**
  5613. * @property initAngularVelocity
  5614. * @type {Vec3}
  5615. */
  5616. this.initAngularVelocity = new Vec3();
  5617. /**
  5618. * @property shapes
  5619. * @type {array}
  5620. */
  5621. this.shapes = [];
  5622. /**
  5623. * @property shapeOffsets
  5624. * @type {array}
  5625. */
  5626. this.shapeOffsets = [];
  5627. /**
  5628. * @property shapeOrientations
  5629. * @type {array}
  5630. */
  5631. this.shapeOrientations = [];
  5632. /**
  5633. * @property inertia
  5634. * @type {Vec3}
  5635. */
  5636. this.inertia = new Vec3();
  5637. /**
  5638. * @property {Vec3} invInertia
  5639. */
  5640. this.invInertia = new Vec3();
  5641. /**
  5642. * @property {Mat3} invInertiaWorld
  5643. */
  5644. this.invInertiaWorld = new Mat3();
  5645. this.invMassSolve = 0;
  5646. /**
  5647. * @property {Vec3} invInertiaSolve
  5648. */
  5649. this.invInertiaSolve = new Vec3();
  5650. /**
  5651. * @property {Mat3} invInertiaWorldSolve
  5652. */
  5653. this.invInertiaWorldSolve = new Mat3();
  5654. /**
  5655. * Set to true if you don't want the body to rotate. Make sure to run .updateMassProperties() after changing this.
  5656. * @property {Boolean} fixedRotation
  5657. * @default false
  5658. */
  5659. this.fixedRotation = typeof(options.fixedRotation) !== "undefined" ? options.fixedRotation : false;
  5660. /**
  5661. * @property {Number} angularDamping
  5662. */
  5663. this.angularDamping = typeof(options.angularDamping) !== 'undefined' ? options.angularDamping : 0.01;
  5664. /**
  5665. * @property {Vec3} linearFactor
  5666. */
  5667. this.linearFactor = new Vec3(1,1,1);
  5668. if(options.linearFactor){
  5669. this.linearFactor.copy(options.linearFactor);
  5670. }
  5671. /**
  5672. * @property {Vec3} angularFactor
  5673. */
  5674. this.angularFactor = new Vec3(1,1,1);
  5675. if(options.angularFactor){
  5676. this.angularFactor.copy(options.angularFactor);
  5677. }
  5678. /**
  5679. * @property aabb
  5680. * @type {AABB}
  5681. */
  5682. this.aabb = new AABB();
  5683. /**
  5684. * Indicates if the AABB needs to be updated before use.
  5685. * @property aabbNeedsUpdate
  5686. * @type {Boolean}
  5687. */
  5688. this.aabbNeedsUpdate = true;
  5689. this.wlambda = new Vec3();
  5690. if(options.shape){
  5691. this.addShape(options.shape);
  5692. }
  5693. this.updateMassProperties();
  5694. }
  5695. Body.prototype = new EventTarget();
  5696. Body.prototype.constructor = Body;
  5697. /**
  5698. * Dispatched after two bodies collide. This event is dispatched on each
  5699. * of the two bodies involved in the collision.
  5700. * @event collide
  5701. * @param {Body} body The body that was involved in the collision.
  5702. * @param {ContactEquation} contact The details of the collision.
  5703. */
  5704. Body.COLLIDE_EVENT_NAME = "collide";
  5705. /**
  5706. * 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.
  5707. * @static
  5708. * @property DYNAMIC
  5709. * @type {Number}
  5710. */
  5711. Body.DYNAMIC = 1;
  5712. /**
  5713. * 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.
  5714. * @static
  5715. * @property STATIC
  5716. * @type {Number}
  5717. */
  5718. Body.STATIC = 2;
  5719. /**
  5720. * 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.
  5721. * @static
  5722. * @property KINEMATIC
  5723. * @type {Number}
  5724. */
  5725. Body.KINEMATIC = 4;
  5726. /**
  5727. * @static
  5728. * @property AWAKE
  5729. * @type {number}
  5730. */
  5731. Body.AWAKE = 0;
  5732. /**
  5733. * @static
  5734. * @property SLEEPY
  5735. * @type {number}
  5736. */
  5737. Body.SLEEPY = 1;
  5738. /**
  5739. * @static
  5740. * @property SLEEPING
  5741. * @type {number}
  5742. */
  5743. Body.SLEEPING = 2;
  5744. Body.idCounter = 0;
  5745. /**
  5746. * Dispatched after a sleeping body has woken up.
  5747. * @event wakeup
  5748. */
  5749. Body.wakeupEvent = {
  5750. type: "wakeup"
  5751. };
  5752. /**
  5753. * Wake the body up.
  5754. * @method wakeUp
  5755. */
  5756. Body.prototype.wakeUp = function(){
  5757. var s = this.sleepState;
  5758. this.sleepState = 0;
  5759. this._wakeUpAfterNarrowphase = false;
  5760. if(s === Body.SLEEPING){
  5761. this.dispatchEvent(Body.wakeupEvent);
  5762. }
  5763. };
  5764. /**
  5765. * Force body sleep
  5766. * @method sleep
  5767. */
  5768. Body.prototype.sleep = function(){
  5769. this.sleepState = Body.SLEEPING;
  5770. this.velocity.set(0,0,0);
  5771. this.angularVelocity.set(0,0,0);
  5772. this._wakeUpAfterNarrowphase = false;
  5773. };
  5774. /**
  5775. * Dispatched after a body has gone in to the sleepy state.
  5776. * @event sleepy
  5777. */
  5778. Body.sleepyEvent = {
  5779. type: "sleepy"
  5780. };
  5781. /**
  5782. * Dispatched after a body has fallen asleep.
  5783. * @event sleep
  5784. */
  5785. Body.sleepEvent = {
  5786. type: "sleep"
  5787. };
  5788. /**
  5789. * Called every timestep to update internal sleep timer and change sleep state if needed.
  5790. * @method sleepTick
  5791. * @param {Number} time The world time in seconds
  5792. */
  5793. Body.prototype.sleepTick = function(time){
  5794. if(this.allowSleep){
  5795. var sleepState = this.sleepState;
  5796. var speedSquared = this.velocity.norm2() + this.angularVelocity.norm2();
  5797. var speedLimitSquared = Math.pow(this.sleepSpeedLimit,2);
  5798. if(sleepState===Body.AWAKE && speedSquared < speedLimitSquared){
  5799. this.sleepState = Body.SLEEPY; // Sleepy
  5800. this.timeLastSleepy = time;
  5801. this.dispatchEvent(Body.sleepyEvent);
  5802. } else if(sleepState===Body.SLEEPY && speedSquared > speedLimitSquared){
  5803. this.wakeUp(); // Wake up
  5804. } else if(sleepState===Body.SLEEPY && (time - this.timeLastSleepy ) > this.sleepTimeLimit){
  5805. this.sleep(); // Sleeping
  5806. this.dispatchEvent(Body.sleepEvent);
  5807. }
  5808. }
  5809. };
  5810. /**
  5811. * If the body is sleeping, it should be immovable / have infinite mass during solve. We solve it by having a separate "solve mass".
  5812. * @method updateSolveMassProperties
  5813. */
  5814. Body.prototype.updateSolveMassProperties = function(){
  5815. if(this.sleepState === Body.SLEEPING || this.type === Body.KINEMATIC){
  5816. this.invMassSolve = 0;
  5817. this.invInertiaSolve.setZero();
  5818. this.invInertiaWorldSolve.setZero();
  5819. } else {
  5820. this.invMassSolve = this.invMass;
  5821. this.invInertiaSolve.copy(this.invInertia);
  5822. this.invInertiaWorldSolve.copy(this.invInertiaWorld);
  5823. }
  5824. };
  5825. /**
  5826. * Convert a world point to local body frame.
  5827. * @method pointToLocalFrame
  5828. * @param {Vec3} worldPoint
  5829. * @param {Vec3} result
  5830. * @return {Vec3}
  5831. */
  5832. Body.prototype.pointToLocalFrame = function(worldPoint,result){
  5833. var result = result || new Vec3();
  5834. worldPoint.vsub(this.position,result);
  5835. this.quaternion.conjugate().vmult(result,result);
  5836. return result;
  5837. };
  5838. /**
  5839. * Convert a world vector to local body frame.
  5840. * @method vectorToLocalFrame
  5841. * @param {Vec3} worldPoint
  5842. * @param {Vec3} result
  5843. * @return {Vec3}
  5844. */
  5845. Body.prototype.vectorToLocalFrame = function(worldVector, result){
  5846. var result = result || new Vec3();
  5847. this.quaternion.conjugate().vmult(worldVector,result);
  5848. return result;
  5849. };
  5850. /**
  5851. * Convert a local body point to world frame.
  5852. * @method pointToWorldFrame
  5853. * @param {Vec3} localPoint
  5854. * @param {Vec3} result
  5855. * @return {Vec3}
  5856. */
  5857. Body.prototype.pointToWorldFrame = function(localPoint,result){
  5858. var result = result || new Vec3();
  5859. this.quaternion.vmult(localPoint,result);
  5860. result.vadd(this.position,result);
  5861. return result;
  5862. };
  5863. /**
  5864. * Convert a local body point to world frame.
  5865. * @method vectorToWorldFrame
  5866. * @param {Vec3} localVector
  5867. * @param {Vec3} result
  5868. * @return {Vec3}
  5869. */
  5870. Body.prototype.vectorToWorldFrame = function(localVector, result){
  5871. var result = result || new Vec3();
  5872. this.quaternion.vmult(localVector, result);
  5873. return result;
  5874. };
  5875. var tmpVec = new Vec3();
  5876. var tmpQuat = new Quaternion();
  5877. /**
  5878. * Add a shape to the body with a local offset and orientation.
  5879. * @method addShape
  5880. * @param {Shape} shape
  5881. * @param {Vec3} [_offset]
  5882. * @param {Quaternion} [_orientation]
  5883. * @return {Body} The body object, for chainability.
  5884. */
  5885. Body.prototype.addShape = function(shape, _offset, _orientation){
  5886. var offset = new Vec3();
  5887. var orientation = new Quaternion();
  5888. if(_offset){
  5889. offset.copy(_offset);
  5890. }
  5891. if(_orientation){
  5892. orientation.copy(_orientation);
  5893. }
  5894. this.shapes.push(shape);
  5895. this.shapeOffsets.push(offset);
  5896. this.shapeOrientations.push(orientation);
  5897. this.updateMassProperties();
  5898. this.updateBoundingRadius();
  5899. this.aabbNeedsUpdate = true;
  5900. shape.body = this;
  5901. return this;
  5902. };
  5903. /**
  5904. * Update the bounding radius of the body. Should be done if any of the shapes are changed.
  5905. * @method updateBoundingRadius
  5906. */
  5907. Body.prototype.updateBoundingRadius = function(){
  5908. var shapes = this.shapes,
  5909. shapeOffsets = this.shapeOffsets,
  5910. N = shapes.length,
  5911. radius = 0;
  5912. for(var i=0; i!==N; i++){
  5913. var shape = shapes[i];
  5914. shape.updateBoundingSphereRadius();
  5915. var offset = shapeOffsets[i].norm(),
  5916. r = shape.boundingSphereRadius;
  5917. if(offset + r > radius){
  5918. radius = offset + r;
  5919. }
  5920. }
  5921. this.boundingRadius = radius;
  5922. };
  5923. var computeAABB_shapeAABB = new AABB();
  5924. /**
  5925. * Updates the .aabb
  5926. * @method computeAABB
  5927. * @todo rename to updateAABB()
  5928. */
  5929. Body.prototype.computeAABB = function(){
  5930. var shapes = this.shapes,
  5931. shapeOffsets = this.shapeOffsets,
  5932. shapeOrientations = this.shapeOrientations,
  5933. N = shapes.length,
  5934. offset = tmpVec,
  5935. orientation = tmpQuat,
  5936. bodyQuat = this.quaternion,
  5937. aabb = this.aabb,
  5938. shapeAABB = computeAABB_shapeAABB;
  5939. for(var i=0; i!==N; i++){
  5940. var shape = shapes[i];
  5941. // Get shape world position
  5942. bodyQuat.vmult(shapeOffsets[i], offset);
  5943. offset.vadd(this.position, offset);
  5944. // Get shape world quaternion
  5945. shapeOrientations[i].mult(bodyQuat, orientation);
  5946. // Get shape AABB
  5947. shape.calculateWorldAABB(offset, orientation, shapeAABB.lowerBound, shapeAABB.upperBound);
  5948. if(i === 0){
  5949. aabb.copy(shapeAABB);
  5950. } else {
  5951. aabb.extend(shapeAABB);
  5952. }
  5953. }
  5954. this.aabbNeedsUpdate = false;
  5955. };
  5956. var uiw_m1 = new Mat3(),
  5957. uiw_m2 = new Mat3(),
  5958. uiw_m3 = new Mat3();
  5959. /**
  5960. * Update .inertiaWorld and .invInertiaWorld
  5961. * @method updateInertiaWorld
  5962. */
  5963. Body.prototype.updateInertiaWorld = function(force){
  5964. var I = this.invInertia;
  5965. if (I.x === I.y && I.y === I.z && !force) {
  5966. // If inertia M = s*I, where I is identity and s a scalar, then
  5967. // R*M*R' = R*(s*I)*R' = s*R*I*R' = s*R*R' = s*I = M
  5968. // where R is the rotation matrix.
  5969. // In other words, we don't have to transform the inertia if all
  5970. // inertia diagonal entries are equal.
  5971. } else {
  5972. var m1 = uiw_m1,
  5973. m2 = uiw_m2,
  5974. m3 = uiw_m3;
  5975. m1.setRotationFromQuaternion(this.quaternion);
  5976. m1.transpose(m2);
  5977. m1.scale(I,m1);
  5978. m1.mmult(m2,this.invInertiaWorld);
  5979. }
  5980. };
  5981. /**
  5982. * 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.
  5983. * @method applyForce
  5984. * @param {Vec3} force The amount of force to add.
  5985. * @param {Vec3} relativePoint A point relative to the center of mass to apply the force on.
  5986. */
  5987. var Body_applyForce_r = new Vec3();
  5988. var Body_applyForce_rotForce = new Vec3();
  5989. Body.prototype.applyForce = function(force,relativePoint){
  5990. if(this.type !== Body.DYNAMIC){ // Needed?
  5991. return;
  5992. }
  5993. // Compute produced rotational force
  5994. var rotForce = Body_applyForce_rotForce;
  5995. relativePoint.cross(force,rotForce);
  5996. // Add linear force
  5997. this.force.vadd(force,this.force);
  5998. // Add rotational force
  5999. this.torque.vadd(rotForce,this.torque);
  6000. };
  6001. /**
  6002. * Apply force to a local point in the body.
  6003. * @method applyLocalForce
  6004. * @param {Vec3} force The force vector to apply, defined locally in the body frame.
  6005. * @param {Vec3} localPoint A local point in the body to apply the force on.
  6006. */
  6007. var Body_applyLocalForce_worldForce = new Vec3();
  6008. var Body_applyLocalForce_relativePointWorld = new Vec3();
  6009. Body.prototype.applyLocalForce = function(localForce, localPoint){
  6010. if(this.type !== Body.DYNAMIC){
  6011. return;
  6012. }
  6013. var worldForce = Body_applyLocalForce_worldForce;
  6014. var relativePointWorld = Body_applyLocalForce_relativePointWorld;
  6015. // Transform the force vector to world space
  6016. this.vectorToWorldFrame(localForce, worldForce);
  6017. this.vectorToWorldFrame(localPoint, relativePointWorld);
  6018. this.applyForce(worldForce, relativePointWorld);
  6019. };
  6020. /**
  6021. * 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.
  6022. * @method applyImpulse
  6023. * @param {Vec3} impulse The amount of impulse to add.
  6024. * @param {Vec3} relativePoint A point relative to the center of mass to apply the force on.
  6025. */
  6026. var Body_applyImpulse_r = new Vec3();
  6027. var Body_applyImpulse_velo = new Vec3();
  6028. var Body_applyImpulse_rotVelo = new Vec3();
  6029. Body.prototype.applyImpulse = function(impulse, relativePoint){
  6030. if(this.type !== Body.DYNAMIC){
  6031. return;
  6032. }
  6033. // Compute point position relative to the body center
  6034. var r = relativePoint;
  6035. // Compute produced central impulse velocity
  6036. var velo = Body_applyImpulse_velo;
  6037. velo.copy(impulse);
  6038. velo.mult(this.invMass,velo);
  6039. // Add linear impulse
  6040. this.velocity.vadd(velo, this.velocity);
  6041. // Compute produced rotational impulse velocity
  6042. var rotVelo = Body_applyImpulse_rotVelo;
  6043. r.cross(impulse,rotVelo);
  6044. /*
  6045. rotVelo.x *= this.invInertia.x;
  6046. rotVelo.y *= this.invInertia.y;
  6047. rotVelo.z *= this.invInertia.z;
  6048. */
  6049. this.invInertiaWorld.vmult(rotVelo,rotVelo);
  6050. // Add rotational Impulse
  6051. this.angularVelocity.vadd(rotVelo, this.angularVelocity);
  6052. };
  6053. /**
  6054. * Apply locally-defined impulse to a local point in the body.
  6055. * @method applyLocalImpulse
  6056. * @param {Vec3} force The force vector to apply, defined locally in the body frame.
  6057. * @param {Vec3} localPoint A local point in the body to apply the force on.
  6058. */
  6059. var Body_applyLocalImpulse_worldImpulse = new Vec3();
  6060. var Body_applyLocalImpulse_relativePoint = new Vec3();
  6061. Body.prototype.applyLocalImpulse = function(localImpulse, localPoint){
  6062. if(this.type !== Body.DYNAMIC){
  6063. return;
  6064. }
  6065. var worldImpulse = Body_applyLocalImpulse_worldImpulse;
  6066. var relativePointWorld = Body_applyLocalImpulse_relativePoint;
  6067. // Transform the force vector to world space
  6068. this.vectorToWorldFrame(localImpulse, worldImpulse);
  6069. this.vectorToWorldFrame(localPoint, relativePointWorld);
  6070. this.applyImpulse(worldImpulse, relativePointWorld);
  6071. };
  6072. var Body_updateMassProperties_halfExtents = new Vec3();
  6073. /**
  6074. * Should be called whenever you change the body shape or mass.
  6075. * @method updateMassProperties
  6076. */
  6077. Body.prototype.updateMassProperties = function(){
  6078. var halfExtents = Body_updateMassProperties_halfExtents;
  6079. this.invMass = this.mass > 0 ? 1.0 / this.mass : 0;
  6080. var I = this.inertia;
  6081. var fixed = this.fixedRotation;
  6082. // Approximate with AABB box
  6083. this.computeAABB();
  6084. halfExtents.set(
  6085. (this.aabb.upperBound.x-this.aabb.lowerBound.x) / 2,
  6086. (this.aabb.upperBound.y-this.aabb.lowerBound.y) / 2,
  6087. (this.aabb.upperBound.z-this.aabb.lowerBound.z) / 2
  6088. );
  6089. Box.calculateInertia(halfExtents, this.mass, I);
  6090. this.invInertia.set(
  6091. I.x > 0 && !fixed ? 1.0 / I.x : 0,
  6092. I.y > 0 && !fixed ? 1.0 / I.y : 0,
  6093. I.z > 0 && !fixed ? 1.0 / I.z : 0
  6094. );
  6095. this.updateInertiaWorld(true);
  6096. };
  6097. /**
  6098. * Get world velocity of a point in the body.
  6099. * @method getVelocityAtWorldPoint
  6100. * @param {Vec3} worldPoint
  6101. * @param {Vec3} result
  6102. * @return {Vec3} The result vector.
  6103. */
  6104. Body.prototype.getVelocityAtWorldPoint = function(worldPoint, result){
  6105. var r = new Vec3();
  6106. worldPoint.vsub(this.position, r);
  6107. this.angularVelocity.cross(r, result);
  6108. this.velocity.vadd(result, result);
  6109. return result;
  6110. };
  6111. var torque = new Vec3();
  6112. var invI_tau_dt = new Vec3();
  6113. var w = new Quaternion();
  6114. var wq = new Quaternion();
  6115. /**
  6116. * Move the body forward in time.
  6117. * @param {number} dt Time step
  6118. * @param {boolean} quatNormalize Set to true to normalize the body quaternion
  6119. * @param {boolean} quatNormalizeFast If the quaternion should be normalized using "fast" quaternion normalization
  6120. */
  6121. Body.prototype.integrate = function(dt, quatNormalize, quatNormalizeFast){
  6122. // Save previous position
  6123. this.previousPosition.copy(this.position);
  6124. this.previousQuaternion.copy(this.quaternion);
  6125. if(!(this.type === Body.DYNAMIC || this.type === Body.KINEMATIC) || this.sleepState === Body.SLEEPING){ // Only for dynamic
  6126. return;
  6127. }
  6128. var velo = this.velocity,
  6129. angularVelo = this.angularVelocity,
  6130. pos = this.position,
  6131. force = this.force,
  6132. torque = this.torque,
  6133. quat = this.quaternion,
  6134. invMass = this.invMass,
  6135. invInertia = this.invInertiaWorld,
  6136. linearFactor = this.linearFactor;
  6137. var iMdt = invMass * dt;
  6138. velo.x += force.x * iMdt * linearFactor.x;
  6139. velo.y += force.y * iMdt * linearFactor.y;
  6140. velo.z += force.z * iMdt * linearFactor.z;
  6141. var e = invInertia.elements;
  6142. var angularFactor = this.angularFactor;
  6143. var tx = torque.x * angularFactor.x;
  6144. var ty = torque.y * angularFactor.y;
  6145. var tz = torque.z * angularFactor.z;
  6146. angularVelo.x += dt * (e[0] * tx + e[1] * ty + e[2] * tz);
  6147. angularVelo.y += dt * (e[3] * tx + e[4] * ty + e[5] * tz);
  6148. angularVelo.z += dt * (e[6] * tx + e[7] * ty + e[8] * tz);
  6149. // Use new velocity - leap frog
  6150. pos.x += velo.x * dt;
  6151. pos.y += velo.y * dt;
  6152. pos.z += velo.z * dt;
  6153. quat.integrate(this.angularVelocity, dt, this.angularFactor, quat);
  6154. if(quatNormalize){
  6155. if(quatNormalizeFast){
  6156. quat.normalizeFast();
  6157. } else {
  6158. quat.normalize();
  6159. }
  6160. }
  6161. this.aabbNeedsUpdate = true;
  6162. // Update world inertia
  6163. this.updateInertiaWorld();
  6164. };
  6165. },{"../collision/AABB":15,"../material/Material":38,"../math/Mat3":40,"../math/Quaternion":41,"../math/Vec3":43,"../shapes/Box":50,"../shapes/Shape":56,"../utils/EventTarget":62}],45:[function(require,module,exports){
  6166. var Body = require('./Body');
  6167. var Vec3 = require('../math/Vec3');
  6168. var Quaternion = require('../math/Quaternion');
  6169. var RaycastResult = require('../collision/RaycastResult');
  6170. var Ray = require('../collision/Ray');
  6171. var WheelInfo = require('../objects/WheelInfo');
  6172. module.exports = RaycastVehicle;
  6173. /**
  6174. * Vehicle helper class that casts rays from the wheel positions towards the ground and applies forces.
  6175. * @class RaycastVehicle
  6176. * @constructor
  6177. * @param {object} [options]
  6178. * @param {Body} [options.chassisBody] The car chassis body.
  6179. * @param {integer} [options.indexRightAxis] Axis to use for right. x=0, y=1, z=2
  6180. * @param {integer} [options.indexLeftAxis]
  6181. * @param {integer} [options.indexUpAxis]
  6182. */
  6183. function RaycastVehicle(options){
  6184. /**
  6185. * @property {Body} chassisBody
  6186. */
  6187. this.chassisBody = options.chassisBody;
  6188. /**
  6189. * An array of WheelInfo objects.
  6190. * @property {array} wheelInfos
  6191. */
  6192. this.wheelInfos = [];
  6193. /**
  6194. * Will be set to true if the car is sliding.
  6195. * @property {boolean} sliding
  6196. */
  6197. this.sliding = false;
  6198. /**
  6199. * @property {World} world
  6200. */
  6201. this.world = null;
  6202. /**
  6203. * Index of the right axis, 0=x, 1=y, 2=z
  6204. * @property {integer} indexRightAxis
  6205. * @default 1
  6206. */
  6207. this.indexRightAxis = typeof(options.indexRightAxis) !== 'undefined' ? options.indexRightAxis : 1;
  6208. /**
  6209. * Index of the forward axis, 0=x, 1=y, 2=z
  6210. * @property {integer} indexForwardAxis
  6211. * @default 0
  6212. */
  6213. this.indexForwardAxis = typeof(options.indexForwardAxis) !== 'undefined' ? options.indexForwardAxis : 0;
  6214. /**
  6215. * Index of the up axis, 0=x, 1=y, 2=z
  6216. * @property {integer} indexUpAxis
  6217. * @default 2
  6218. */
  6219. this.indexUpAxis = typeof(options.indexUpAxis) !== 'undefined' ? options.indexUpAxis : 2;
  6220. }
  6221. var tmpVec1 = new Vec3();
  6222. var tmpVec2 = new Vec3();
  6223. var tmpVec3 = new Vec3();
  6224. var tmpVec4 = new Vec3();
  6225. var tmpVec5 = new Vec3();
  6226. var tmpVec6 = new Vec3();
  6227. var tmpRay = new Ray();
  6228. /**
  6229. * Add a wheel. For information about the options, see WheelInfo.
  6230. * @method addWheel
  6231. * @param {object} [options]
  6232. */
  6233. RaycastVehicle.prototype.addWheel = function(options){
  6234. options = options || {};
  6235. var info = new WheelInfo(options);
  6236. var index = this.wheelInfos.length;
  6237. this.wheelInfos.push(info);
  6238. return index;
  6239. };
  6240. /**
  6241. * Set the steering value of a wheel.
  6242. * @method setSteeringValue
  6243. * @param {number} value
  6244. * @param {integer} wheelIndex
  6245. */
  6246. RaycastVehicle.prototype.setSteeringValue = function(value, wheelIndex){
  6247. var wheel = this.wheelInfos[wheelIndex];
  6248. wheel.steering = value;
  6249. };
  6250. var torque = new Vec3();
  6251. /**
  6252. * Set the wheel force to apply on one of the wheels each time step
  6253. * @method applyEngineForce
  6254. * @param {number} value
  6255. * @param {integer} wheelIndex
  6256. */
  6257. RaycastVehicle.prototype.applyEngineForce = function(value, wheelIndex){
  6258. this.wheelInfos[wheelIndex].engineForce = value;
  6259. };
  6260. /**
  6261. * Set the braking force of a wheel
  6262. * @method setBrake
  6263. * @param {number} brake
  6264. * @param {integer} wheelIndex
  6265. */
  6266. RaycastVehicle.prototype.setBrake = function(brake, wheelIndex){
  6267. this.wheelInfos[wheelIndex].brake = brake;
  6268. };
  6269. /**
  6270. * Add the vehicle including its constraints to the world.
  6271. * @method addToWorld
  6272. * @param {World} world
  6273. */
  6274. RaycastVehicle.prototype.addToWorld = function(world){
  6275. var constraints = this.constraints;
  6276. world.addBody(this.chassisBody);
  6277. var that = this;
  6278. this.preStepCallback = function(){
  6279. that.updateVehicle(world.dt);
  6280. };
  6281. world.addEventListener('preStep', this.preStepCallback);
  6282. this.world = world;
  6283. };
  6284. /**
  6285. * Get one of the wheel axles, world-oriented.
  6286. * @private
  6287. * @method getVehicleAxisWorld
  6288. * @param {integer} axisIndex
  6289. * @param {Vec3} result
  6290. */
  6291. RaycastVehicle.prototype.getVehicleAxisWorld = function(axisIndex, result){
  6292. result.set(
  6293. axisIndex === 0 ? 1 : 0,
  6294. axisIndex === 1 ? 1 : 0,
  6295. axisIndex === 2 ? 1 : 0
  6296. );
  6297. this.chassisBody.vectorToWorldFrame(result, result);
  6298. };
  6299. RaycastVehicle.prototype.updateVehicle = function(timeStep){
  6300. var wheelInfos = this.wheelInfos;
  6301. var numWheels = wheelInfos.length;
  6302. var chassisBody = this.chassisBody;
  6303. for (var i = 0; i < numWheels; i++) {
  6304. this.updateWheelTransform(i);
  6305. }
  6306. this.currentVehicleSpeedKmHour = 3.6 * chassisBody.velocity.norm();
  6307. var forwardWorld = new Vec3();
  6308. this.getVehicleAxisWorld(this.indexForwardAxis, forwardWorld);
  6309. if (forwardWorld.dot(chassisBody.velocity) < 0){
  6310. this.currentVehicleSpeedKmHour *= -1;
  6311. }
  6312. // simulate suspension
  6313. for (var i = 0; i < numWheels; i++) {
  6314. this.castRay(wheelInfos[i]);
  6315. }
  6316. this.updateSuspension(timeStep);
  6317. var impulse = new Vec3();
  6318. var relpos = new Vec3();
  6319. for (var i = 0; i < numWheels; i++) {
  6320. //apply suspension force
  6321. var wheel = wheelInfos[i];
  6322. var suspensionForce = wheel.suspensionForce;
  6323. if (suspensionForce > wheel.maxSuspensionForce) {
  6324. suspensionForce = wheel.maxSuspensionForce;
  6325. }
  6326. wheel.raycastResult.hitNormalWorld.scale(suspensionForce * timeStep, impulse);
  6327. wheel.raycastResult.hitPointWorld.vsub(chassisBody.position, relpos);
  6328. chassisBody.applyImpulse(impulse, relpos);
  6329. }
  6330. this.updateFriction(timeStep);
  6331. var hitNormalWorldScaledWithProj = new Vec3();
  6332. var fwd = new Vec3();
  6333. var vel = new Vec3();
  6334. for (i = 0; i < numWheels; i++) {
  6335. var wheel = wheelInfos[i];
  6336. //var relpos = new Vec3();
  6337. //wheel.chassisConnectionPointWorld.vsub(chassisBody.position, relpos);
  6338. chassisBody.getVelocityAtWorldPoint(wheel.chassisConnectionPointWorld, vel);
  6339. // Hack to get the rotation in the correct direction
  6340. var m = 1;
  6341. switch(this.indexUpAxis){
  6342. case 1:
  6343. m = -1;
  6344. break;
  6345. }
  6346. if (wheel.isInContact) {
  6347. this.getVehicleAxisWorld(this.indexForwardAxis, fwd);
  6348. var proj = fwd.dot(wheel.raycastResult.hitNormalWorld);
  6349. wheel.raycastResult.hitNormalWorld.scale(proj, hitNormalWorldScaledWithProj);
  6350. fwd.vsub(hitNormalWorldScaledWithProj, fwd);
  6351. var proj2 = fwd.dot(vel);
  6352. wheel.deltaRotation = m * proj2 * timeStep / wheel.radius;
  6353. }
  6354. if((wheel.sliding || !wheel.isInContact) && wheel.engineForce !== 0 && wheel.useCustomSlidingRotationalSpeed){
  6355. // Apply custom rotation when accelerating and sliding
  6356. wheel.deltaRotation = (wheel.engineForce > 0 ? 1 : -1) * wheel.customSlidingRotationalSpeed * timeStep;
  6357. }
  6358. // Lock wheels
  6359. if(Math.abs(wheel.brake) > Math.abs(wheel.engineForce)){
  6360. wheel.deltaRotation = 0;
  6361. }
  6362. wheel.rotation += wheel.deltaRotation; // Use the old value
  6363. wheel.deltaRotation *= 0.99; // damping of rotation when not in contact
  6364. }
  6365. };
  6366. RaycastVehicle.prototype.updateSuspension = function(deltaTime) {
  6367. var chassisBody = this.chassisBody;
  6368. var chassisMass = chassisBody.mass;
  6369. var wheelInfos = this.wheelInfos;
  6370. var numWheels = wheelInfos.length;
  6371. for (var w_it = 0; w_it < numWheels; w_it++){
  6372. var wheel = wheelInfos[w_it];
  6373. if (wheel.isInContact){
  6374. var force;
  6375. // Spring
  6376. var susp_length = wheel.suspensionRestLength;
  6377. var current_length = wheel.suspensionLength;
  6378. var length_diff = (susp_length - current_length);
  6379. force = wheel.suspensionStiffness * length_diff * wheel.clippedInvContactDotSuspension;
  6380. // Damper
  6381. var projected_rel_vel = wheel.suspensionRelativeVelocity;
  6382. var susp_damping;
  6383. if (projected_rel_vel < 0) {
  6384. susp_damping = wheel.dampingCompression;
  6385. } else {
  6386. susp_damping = wheel.dampingRelaxation;
  6387. }
  6388. force -= susp_damping * projected_rel_vel;
  6389. wheel.suspensionForce = force * chassisMass;
  6390. if (wheel.suspensionForce < 0) {
  6391. wheel.suspensionForce = 0;
  6392. }
  6393. } else {
  6394. wheel.suspensionForce = 0;
  6395. }
  6396. }
  6397. };
  6398. /**
  6399. * Remove the vehicle including its constraints from the world.
  6400. * @method removeFromWorld
  6401. * @param {World} world
  6402. */
  6403. RaycastVehicle.prototype.removeFromWorld = function(world){
  6404. var constraints = this.constraints;
  6405. world.remove(this.chassisBody);
  6406. world.removeEventListener('preStep', this.preStepCallback);
  6407. this.world = null;
  6408. };
  6409. var castRay_rayvector = new Vec3();
  6410. var castRay_target = new Vec3();
  6411. RaycastVehicle.prototype.castRay = function(wheel) {
  6412. var rayvector = castRay_rayvector;
  6413. var target = castRay_target;
  6414. this.updateWheelTransformWorld(wheel);
  6415. var chassisBody = this.chassisBody;
  6416. var depth = -1;
  6417. var raylen = wheel.suspensionRestLength + wheel.radius;
  6418. wheel.directionWorld.scale(raylen, rayvector);
  6419. var source = wheel.chassisConnectionPointWorld;
  6420. source.vadd(rayvector, target);
  6421. var raycastResult = wheel.raycastResult;
  6422. var param = 0;
  6423. raycastResult.reset();
  6424. // Turn off ray collision with the chassis temporarily
  6425. var oldState = chassisBody.collisionResponse;
  6426. chassisBody.collisionResponse = false;
  6427. // Cast ray against world
  6428. this.world.rayTest(source, target, raycastResult);
  6429. chassisBody.collisionResponse = oldState;
  6430. var object = raycastResult.body;
  6431. wheel.raycastResult.groundObject = 0;
  6432. if (object) {
  6433. depth = raycastResult.distance;
  6434. wheel.raycastResult.hitNormalWorld = raycastResult.hitNormalWorld;
  6435. wheel.isInContact = true;
  6436. var hitDistance = raycastResult.distance;
  6437. wheel.suspensionLength = hitDistance - wheel.radius;
  6438. // clamp on max suspension travel
  6439. var minSuspensionLength = wheel.suspensionRestLength - wheel.maxSuspensionTravel;
  6440. var maxSuspensionLength = wheel.suspensionRestLength + wheel.maxSuspensionTravel;
  6441. if (wheel.suspensionLength < minSuspensionLength) {
  6442. wheel.suspensionLength = minSuspensionLength;
  6443. }
  6444. if (wheel.suspensionLength > maxSuspensionLength) {
  6445. wheel.suspensionLength = maxSuspensionLength;
  6446. wheel.raycastResult.reset();
  6447. }
  6448. var denominator = wheel.raycastResult.hitNormalWorld.dot(wheel.directionWorld);
  6449. var chassis_velocity_at_contactPoint = new Vec3();
  6450. chassisBody.getVelocityAtWorldPoint(wheel.raycastResult.hitPointWorld, chassis_velocity_at_contactPoint);
  6451. var projVel = wheel.raycastResult.hitNormalWorld.dot( chassis_velocity_at_contactPoint );
  6452. if (denominator >= -0.1) {
  6453. wheel.suspensionRelativeVelocity = 0;
  6454. wheel.clippedInvContactDotSuspension = 1 / 0.1;
  6455. } else {
  6456. var inv = -1 / denominator;
  6457. wheel.suspensionRelativeVelocity = projVel * inv;
  6458. wheel.clippedInvContactDotSuspension = inv;
  6459. }
  6460. } else {
  6461. //put wheel info as in rest position
  6462. wheel.suspensionLength = wheel.suspensionRestLength + 0 * wheel.maxSuspensionTravel;
  6463. wheel.suspensionRelativeVelocity = 0.0;
  6464. wheel.directionWorld.scale(-1, wheel.raycastResult.hitNormalWorld);
  6465. wheel.clippedInvContactDotSuspension = 1.0;
  6466. }
  6467. return depth;
  6468. };
  6469. RaycastVehicle.prototype.updateWheelTransformWorld = function(wheel){
  6470. wheel.isInContact = false;
  6471. var chassisBody = this.chassisBody;
  6472. chassisBody.pointToWorldFrame(wheel.chassisConnectionPointLocal, wheel.chassisConnectionPointWorld);
  6473. chassisBody.vectorToWorldFrame(wheel.directionLocal, wheel.directionWorld);
  6474. chassisBody.vectorToWorldFrame(wheel.axleLocal, wheel.axleWorld);
  6475. };
  6476. /**
  6477. * Update one of the wheel transform.
  6478. * 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.
  6479. * @method updateWheelTransform
  6480. * @param {integer} wheelIndex The wheel index to update.
  6481. */
  6482. RaycastVehicle.prototype.updateWheelTransform = function(wheelIndex){
  6483. var up = tmpVec4;
  6484. var right = tmpVec5;
  6485. var fwd = tmpVec6;
  6486. var wheel = this.wheelInfos[wheelIndex];
  6487. this.updateWheelTransformWorld(wheel);
  6488. wheel.directionLocal.scale(-1, up);
  6489. right.copy(wheel.axleLocal);
  6490. up.cross(right, fwd);
  6491. fwd.normalize();
  6492. right.normalize();
  6493. // Rotate around steering over the wheelAxle
  6494. var steering = wheel.steering;
  6495. var steeringOrn = new Quaternion();
  6496. steeringOrn.setFromAxisAngle(up, steering);
  6497. var rotatingOrn = new Quaternion();
  6498. rotatingOrn.setFromAxisAngle(right, wheel.rotation);
  6499. // World rotation of the wheel
  6500. var q = wheel.worldTransform.quaternion;
  6501. this.chassisBody.quaternion.mult(steeringOrn, q);
  6502. q.mult(rotatingOrn, q);
  6503. q.normalize();
  6504. // world position of the wheel
  6505. var p = wheel.worldTransform.position;
  6506. p.copy(wheel.directionWorld);
  6507. p.scale(wheel.suspensionLength, p);
  6508. p.vadd(wheel.chassisConnectionPointWorld, p);
  6509. };
  6510. var directions = [
  6511. new Vec3(1, 0, 0),
  6512. new Vec3(0, 1, 0),
  6513. new Vec3(0, 0, 1)
  6514. ];
  6515. /**
  6516. * Get the world transform of one of the wheels
  6517. * @method getWheelTransformWorld
  6518. * @param {integer} wheelIndex
  6519. * @return {Transform}
  6520. */
  6521. RaycastVehicle.prototype.getWheelTransformWorld = function(wheelIndex) {
  6522. return this.wheelInfos[wheelIndex].worldTransform;
  6523. };
  6524. var updateFriction_surfNormalWS_scaled_proj = new Vec3();
  6525. var updateFriction_axle = [];
  6526. var updateFriction_forwardWS = [];
  6527. var sideFrictionStiffness2 = 1;
  6528. RaycastVehicle.prototype.updateFriction = function(timeStep) {
  6529. var surfNormalWS_scaled_proj = updateFriction_surfNormalWS_scaled_proj;
  6530. //calculate the impulse, so that the wheels don't move sidewards
  6531. var wheelInfos = this.wheelInfos;
  6532. var numWheels = wheelInfos.length;
  6533. var chassisBody = this.chassisBody;
  6534. var forwardWS = updateFriction_forwardWS;
  6535. var axle = updateFriction_axle;
  6536. var numWheelsOnGround = 0;
  6537. for (var i = 0; i < numWheels; i++) {
  6538. var wheel = wheelInfos[i];
  6539. var groundObject = wheel.raycastResult.body;
  6540. if (groundObject){
  6541. numWheelsOnGround++;
  6542. }
  6543. wheel.sideImpulse = 0;
  6544. wheel.forwardImpulse = 0;
  6545. if(!forwardWS[i]){
  6546. forwardWS[i] = new Vec3();
  6547. }
  6548. if(!axle[i]){
  6549. axle[i] = new Vec3();
  6550. }
  6551. }
  6552. for (var i = 0; i < numWheels; i++){
  6553. var wheel = wheelInfos[i];
  6554. var groundObject = wheel.raycastResult.body;
  6555. if (groundObject) {
  6556. var axlei = axle[i];
  6557. var wheelTrans = this.getWheelTransformWorld(i);
  6558. // Get world axle
  6559. wheelTrans.vectorToWorldFrame(directions[this.indexRightAxis], axlei);
  6560. var surfNormalWS = wheel.raycastResult.hitNormalWorld;
  6561. var proj = axlei.dot(surfNormalWS);
  6562. surfNormalWS.scale(proj, surfNormalWS_scaled_proj);
  6563. axlei.vsub(surfNormalWS_scaled_proj, axlei);
  6564. axlei.normalize();
  6565. surfNormalWS.cross(axlei, forwardWS[i]);
  6566. forwardWS[i].normalize();
  6567. wheel.sideImpulse = resolveSingleBilateral(
  6568. chassisBody,
  6569. wheel.raycastResult.hitPointWorld,
  6570. groundObject,
  6571. wheel.raycastResult.hitPointWorld,
  6572. axlei
  6573. );
  6574. wheel.sideImpulse *= sideFrictionStiffness2;
  6575. }
  6576. }
  6577. var sideFactor = 1;
  6578. var fwdFactor = 0.5;
  6579. this.sliding = false;
  6580. for (var i = 0; i < numWheels; i++) {
  6581. var wheel = wheelInfos[i];
  6582. var groundObject = wheel.raycastResult.body;
  6583. var rollingFriction = 0;
  6584. wheel.slipInfo = 1;
  6585. if (groundObject) {
  6586. var defaultRollingFrictionImpulse = 0;
  6587. var maxImpulse = wheel.brake ? wheel.brake : defaultRollingFrictionImpulse;
  6588. // btWheelContactPoint contactPt(chassisBody,groundObject,wheelInfraycastInfo.hitPointWorld,forwardWS[wheel],maxImpulse);
  6589. // rollingFriction = calcRollingFriction(contactPt);
  6590. rollingFriction = calcRollingFriction(chassisBody, groundObject, wheel.raycastResult.hitPointWorld, forwardWS[i], maxImpulse);
  6591. rollingFriction += wheel.engineForce * timeStep;
  6592. // rollingFriction = 0;
  6593. var factor = maxImpulse / rollingFriction;
  6594. wheel.slipInfo *= factor;
  6595. }
  6596. //switch between active rolling (throttle), braking and non-active rolling friction (nthrottle/break)
  6597. wheel.forwardImpulse = 0;
  6598. wheel.skidInfo = 1;
  6599. if (groundObject) {
  6600. wheel.skidInfo = 1;
  6601. var maximp = wheel.suspensionForce * timeStep * wheel.frictionSlip;
  6602. var maximpSide = maximp;
  6603. var maximpSquared = maximp * maximpSide;
  6604. wheel.forwardImpulse = rollingFriction;//wheelInfo.engineForce* timeStep;
  6605. var x = wheel.forwardImpulse * fwdFactor;
  6606. var y = wheel.sideImpulse * sideFactor;
  6607. var impulseSquared = x * x + y * y;
  6608. wheel.sliding = false;
  6609. if (impulseSquared > maximpSquared) {
  6610. this.sliding = true;
  6611. wheel.sliding = true;
  6612. var factor = maximp / Math.sqrt(impulseSquared);
  6613. wheel.skidInfo *= factor;
  6614. }
  6615. }
  6616. }
  6617. if (this.sliding) {
  6618. for (var i = 0; i < numWheels; i++) {
  6619. var wheel = wheelInfos[i];
  6620. if (wheel.sideImpulse !== 0) {
  6621. if (wheel.skidInfo < 1){
  6622. wheel.forwardImpulse *= wheel.skidInfo;
  6623. wheel.sideImpulse *= wheel.skidInfo;
  6624. }
  6625. }
  6626. }
  6627. }
  6628. // apply the impulses
  6629. for (var i = 0; i < numWheels; i++) {
  6630. var wheel = wheelInfos[i];
  6631. var rel_pos = new Vec3();
  6632. wheel.raycastResult.hitPointWorld.vsub(chassisBody.position, rel_pos);
  6633. // cannons applyimpulse is using world coord for the position
  6634. //rel_pos.copy(wheel.raycastResult.hitPointWorld);
  6635. if (wheel.forwardImpulse !== 0) {
  6636. var impulse = new Vec3();
  6637. forwardWS[i].scale(wheel.forwardImpulse, impulse);
  6638. chassisBody.applyImpulse(impulse, rel_pos);
  6639. }
  6640. if (wheel.sideImpulse !== 0){
  6641. var groundObject = wheel.raycastResult.body;
  6642. var rel_pos2 = new Vec3();
  6643. wheel.raycastResult.hitPointWorld.vsub(groundObject.position, rel_pos2);
  6644. //rel_pos2.copy(wheel.raycastResult.hitPointWorld);
  6645. var sideImp = new Vec3();
  6646. axle[i].scale(wheel.sideImpulse, sideImp);
  6647. // Scale the relative position in the up direction with rollInfluence.
  6648. // 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).
  6649. chassisBody.vectorToLocalFrame(rel_pos, rel_pos);
  6650. rel_pos['xyz'[this.indexUpAxis]] *= wheel.rollInfluence;
  6651. chassisBody.vectorToWorldFrame(rel_pos, rel_pos);
  6652. chassisBody.applyImpulse(sideImp, rel_pos);
  6653. //apply friction impulse on the ground
  6654. sideImp.scale(-1, sideImp);
  6655. groundObject.applyImpulse(sideImp, rel_pos2);
  6656. }
  6657. }
  6658. };
  6659. var calcRollingFriction_vel1 = new Vec3();
  6660. var calcRollingFriction_vel2 = new Vec3();
  6661. var calcRollingFriction_vel = new Vec3();
  6662. function calcRollingFriction(body0, body1, frictionPosWorld, frictionDirectionWorld, maxImpulse) {
  6663. var j1 = 0;
  6664. var contactPosWorld = frictionPosWorld;
  6665. // var rel_pos1 = new Vec3();
  6666. // var rel_pos2 = new Vec3();
  6667. var vel1 = calcRollingFriction_vel1;
  6668. var vel2 = calcRollingFriction_vel2;
  6669. var vel = calcRollingFriction_vel;
  6670. // contactPosWorld.vsub(body0.position, rel_pos1);
  6671. // contactPosWorld.vsub(body1.position, rel_pos2);
  6672. body0.getVelocityAtWorldPoint(contactPosWorld, vel1);
  6673. body1.getVelocityAtWorldPoint(contactPosWorld, vel2);
  6674. vel1.vsub(vel2, vel);
  6675. var vrel = frictionDirectionWorld.dot(vel);
  6676. var denom0 = computeImpulseDenominator(body0, frictionPosWorld, frictionDirectionWorld);
  6677. var denom1 = computeImpulseDenominator(body1, frictionPosWorld, frictionDirectionWorld);
  6678. var relaxation = 1;
  6679. var jacDiagABInv = relaxation / (denom0 + denom1);
  6680. // calculate j that moves us to zero relative velocity
  6681. j1 = -vrel * jacDiagABInv;
  6682. if (maxImpulse < j1) {
  6683. j1 = maxImpulse;
  6684. }
  6685. if (j1 < -maxImpulse) {
  6686. j1 = -maxImpulse;
  6687. }
  6688. return j1;
  6689. }
  6690. var computeImpulseDenominator_r0 = new Vec3();
  6691. var computeImpulseDenominator_c0 = new Vec3();
  6692. var computeImpulseDenominator_vec = new Vec3();
  6693. var computeImpulseDenominator_m = new Vec3();
  6694. function computeImpulseDenominator(body, pos, normal) {
  6695. var r0 = computeImpulseDenominator_r0;
  6696. var c0 = computeImpulseDenominator_c0;
  6697. var vec = computeImpulseDenominator_vec;
  6698. var m = computeImpulseDenominator_m;
  6699. pos.vsub(body.position, r0);
  6700. r0.cross(normal, c0);
  6701. body.invInertiaWorld.vmult(c0, m);
  6702. m.cross(r0, vec);
  6703. return body.invMass + normal.dot(vec);
  6704. }
  6705. var resolveSingleBilateral_vel1 = new Vec3();
  6706. var resolveSingleBilateral_vel2 = new Vec3();
  6707. var resolveSingleBilateral_vel = new Vec3();
  6708. //bilateral constraint between two dynamic objects
  6709. function resolveSingleBilateral(body1, pos1, body2, pos2, normal, impulse){
  6710. var normalLenSqr = normal.norm2();
  6711. if (normalLenSqr > 1.1){
  6712. return 0; // no impulse
  6713. }
  6714. // var rel_pos1 = new Vec3();
  6715. // var rel_pos2 = new Vec3();
  6716. // pos1.vsub(body1.position, rel_pos1);
  6717. // pos2.vsub(body2.position, rel_pos2);
  6718. var vel1 = resolveSingleBilateral_vel1;
  6719. var vel2 = resolveSingleBilateral_vel2;
  6720. var vel = resolveSingleBilateral_vel;
  6721. body1.getVelocityAtWorldPoint(pos1, vel1);
  6722. body2.getVelocityAtWorldPoint(pos2, vel2);
  6723. vel1.vsub(vel2, vel);
  6724. var rel_vel = normal.dot(vel);
  6725. var contactDamping = 0.2;
  6726. var massTerm = 1 / (body1.invMass + body2.invMass);
  6727. var impulse = - contactDamping * rel_vel * massTerm;
  6728. return impulse;
  6729. }
  6730. },{"../collision/Ray":22,"../collision/RaycastResult":23,"../math/Quaternion":41,"../math/Vec3":43,"../objects/WheelInfo":49,"./Body":44}],46:[function(require,module,exports){
  6731. var Body = require('./Body');
  6732. var Sphere = require('../shapes/Sphere');
  6733. var Box = require('../shapes/Box');
  6734. var Vec3 = require('../math/Vec3');
  6735. var HingeConstraint = require('../constraints/HingeConstraint');
  6736. module.exports = RigidVehicle;
  6737. /**
  6738. * Simple vehicle helper class with spherical rigid body wheels.
  6739. * @class RigidVehicle
  6740. * @constructor
  6741. * @param {Body} [options.chassisBody]
  6742. */
  6743. function RigidVehicle(options){
  6744. this.wheelBodies = [];
  6745. /**
  6746. * @property coordinateSystem
  6747. * @type {Vec3}
  6748. */
  6749. this.coordinateSystem = typeof(options.coordinateSystem)==='undefined' ? new Vec3(1, 2, 3) : options.coordinateSystem.clone();
  6750. /**
  6751. * @property {Body} chassisBody
  6752. */
  6753. this.chassisBody = options.chassisBody;
  6754. if(!this.chassisBody){
  6755. // No chassis body given. Create it!
  6756. var chassisShape = new Box(new Vec3(5, 2, 0.5));
  6757. this.chassisBody = new Body(1, chassisShape);
  6758. }
  6759. /**
  6760. * @property constraints
  6761. * @type {Array}
  6762. */
  6763. this.constraints = [];
  6764. this.wheelAxes = [];
  6765. this.wheelForces = [];
  6766. }
  6767. /**
  6768. * Add a wheel
  6769. * @method addWheel
  6770. * @param {object} options
  6771. * @param {boolean} [options.isFrontWheel]
  6772. * @param {Vec3} [options.position] Position of the wheel, locally in the chassis body.
  6773. * @param {Vec3} [options.direction] Slide direction of the wheel along the suspension.
  6774. * @param {Vec3} [options.axis] Axis of rotation of the wheel, locally defined in the chassis.
  6775. * @param {Body} [options.body] The wheel body.
  6776. */
  6777. RigidVehicle.prototype.addWheel = function(options){
  6778. options = options || {};
  6779. var wheelBody = options.body;
  6780. if(!wheelBody){
  6781. wheelBody = new Body(1, new Sphere(1.2));
  6782. }
  6783. this.wheelBodies.push(wheelBody);
  6784. this.wheelForces.push(0);
  6785. // Position constrain wheels
  6786. var zero = new Vec3();
  6787. var position = typeof(options.position) !== 'undefined' ? options.position.clone() : new Vec3();
  6788. // Set position locally to the chassis
  6789. var worldPosition = new Vec3();
  6790. this.chassisBody.pointToWorldFrame(position, worldPosition);
  6791. wheelBody.position.set(worldPosition.x, worldPosition.y, worldPosition.z);
  6792. // Constrain wheel
  6793. var axis = typeof(options.axis) !== 'undefined' ? options.axis.clone() : new Vec3(0, 1, 0);
  6794. this.wheelAxes.push(axis);
  6795. var hingeConstraint = new HingeConstraint(this.chassisBody, wheelBody, {
  6796. pivotA: position,
  6797. axisA: axis,
  6798. pivotB: Vec3.ZERO,
  6799. axisB: axis,
  6800. collideConnected: false
  6801. });
  6802. this.constraints.push(hingeConstraint);
  6803. return this.wheelBodies.length - 1;
  6804. };
  6805. /**
  6806. * Set the steering value of a wheel.
  6807. * @method setSteeringValue
  6808. * @param {number} value
  6809. * @param {integer} wheelIndex
  6810. * @todo check coordinateSystem
  6811. */
  6812. RigidVehicle.prototype.setSteeringValue = function(value, wheelIndex){
  6813. // Set angle of the hinge axis
  6814. var axis = this.wheelAxes[wheelIndex];
  6815. var c = Math.cos(value),
  6816. s = Math.sin(value),
  6817. x = axis.x,
  6818. y = axis.y;
  6819. this.constraints[wheelIndex].axisA.set(
  6820. c*x -s*y,
  6821. s*x +c*y,
  6822. 0
  6823. );
  6824. };
  6825. /**
  6826. * Set the target rotational speed of the hinge constraint.
  6827. * @method setMotorSpeed
  6828. * @param {number} value
  6829. * @param {integer} wheelIndex
  6830. */
  6831. RigidVehicle.prototype.setMotorSpeed = function(value, wheelIndex){
  6832. var hingeConstraint = this.constraints[wheelIndex];
  6833. hingeConstraint.enableMotor();
  6834. hingeConstraint.motorTargetVelocity = value;
  6835. };
  6836. /**
  6837. * Set the target rotational speed of the hinge constraint.
  6838. * @method disableMotor
  6839. * @param {number} value
  6840. * @param {integer} wheelIndex
  6841. */
  6842. RigidVehicle.prototype.disableMotor = function(wheelIndex){
  6843. var hingeConstraint = this.constraints[wheelIndex];
  6844. hingeConstraint.disableMotor();
  6845. };
  6846. var torque = new Vec3();
  6847. /**
  6848. * Set the wheel force to apply on one of the wheels each time step
  6849. * @method setWheelForce
  6850. * @param {number} value
  6851. * @param {integer} wheelIndex
  6852. */
  6853. RigidVehicle.prototype.setWheelForce = function(value, wheelIndex){
  6854. this.wheelForces[wheelIndex] = value;
  6855. };
  6856. /**
  6857. * Apply a torque on one of the wheels.
  6858. * @method applyWheelForce
  6859. * @param {number} value
  6860. * @param {integer} wheelIndex
  6861. */
  6862. RigidVehicle.prototype.applyWheelForce = function(value, wheelIndex){
  6863. var axis = this.wheelAxes[wheelIndex];
  6864. var wheelBody = this.wheelBodies[wheelIndex];
  6865. var bodyTorque = wheelBody.torque;
  6866. axis.scale(value, torque);
  6867. wheelBody.vectorToWorldFrame(torque, torque);
  6868. bodyTorque.vadd(torque, bodyTorque);
  6869. };
  6870. /**
  6871. * Add the vehicle including its constraints to the world.
  6872. * @method addToWorld
  6873. * @param {World} world
  6874. */
  6875. RigidVehicle.prototype.addToWorld = function(world){
  6876. var constraints = this.constraints;
  6877. var bodies = this.wheelBodies.concat([this.chassisBody]);
  6878. for (var i = 0; i < bodies.length; i++) {
  6879. world.addBody(bodies[i]);
  6880. }
  6881. for (var i = 0; i < constraints.length; i++) {
  6882. world.addConstraint(constraints[i]);
  6883. }
  6884. world.addEventListener('preStep', this._update.bind(this));
  6885. };
  6886. RigidVehicle.prototype._update = function(){
  6887. var wheelForces = this.wheelForces;
  6888. for (var i = 0; i < wheelForces.length; i++) {
  6889. this.applyWheelForce(wheelForces[i], i);
  6890. }
  6891. };
  6892. /**
  6893. * Remove the vehicle including its constraints from the world.
  6894. * @method removeFromWorld
  6895. * @param {World} world
  6896. */
  6897. RigidVehicle.prototype.removeFromWorld = function(world){
  6898. var constraints = this.constraints;
  6899. var bodies = this.wheelBodies.concat([this.chassisBody]);
  6900. for (var i = 0; i < bodies.length; i++) {
  6901. world.remove(bodies[i]);
  6902. }
  6903. for (var i = 0; i < constraints.length; i++) {
  6904. world.removeConstraint(constraints[i]);
  6905. }
  6906. };
  6907. var worldAxis = new Vec3();
  6908. /**
  6909. * Get current rotational velocity of a wheel
  6910. * @method getWheelSpeed
  6911. * @param {integer} wheelIndex
  6912. */
  6913. RigidVehicle.prototype.getWheelSpeed = function(wheelIndex){
  6914. var axis = this.wheelAxes[wheelIndex];
  6915. var wheelBody = this.wheelBodies[wheelIndex];
  6916. var w = wheelBody.angularVelocity;
  6917. this.chassisBody.vectorToWorldFrame(axis, worldAxis);
  6918. return w.dot(worldAxis);
  6919. };
  6920. },{"../constraints/HingeConstraint":28,"../math/Vec3":43,"../shapes/Box":50,"../shapes/Sphere":57,"./Body":44}],47:[function(require,module,exports){
  6921. module.exports = SPHSystem;
  6922. var Shape = require('../shapes/Shape');
  6923. var Vec3 = require('../math/Vec3');
  6924. var Quaternion = require('../math/Quaternion');
  6925. var Particle = require('../shapes/Particle');
  6926. var Body = require('../objects/Body');
  6927. var Material = require('../material/Material');
  6928. /**
  6929. * Smoothed-particle hydrodynamics system
  6930. * @class SPHSystem
  6931. * @constructor
  6932. */
  6933. function SPHSystem(){
  6934. this.particles = [];
  6935. /**
  6936. * Density of the system (kg/m3).
  6937. * @property {number} density
  6938. */
  6939. this.density = 1;
  6940. /**
  6941. * Distance below which two particles are considered to be neighbors.
  6942. * It should be adjusted so there are about 15-20 neighbor particles within this radius.
  6943. * @property {number} smoothingRadius
  6944. */
  6945. this.smoothingRadius = 1;
  6946. this.speedOfSound = 1;
  6947. /**
  6948. * Viscosity of the system.
  6949. * @property {number} viscosity
  6950. */
  6951. this.viscosity = 0.01;
  6952. this.eps = 0.000001;
  6953. // Stuff Computed per particle
  6954. this.pressures = [];
  6955. this.densities = [];
  6956. this.neighbors = [];
  6957. }
  6958. /**
  6959. * Add a particle to the system.
  6960. * @method add
  6961. * @param {Body} particle
  6962. */
  6963. SPHSystem.prototype.add = function(particle){
  6964. this.particles.push(particle);
  6965. if(this.neighbors.length < this.particles.length){
  6966. this.neighbors.push([]);
  6967. }
  6968. };
  6969. /**
  6970. * Remove a particle from the system.
  6971. * @method remove
  6972. * @param {Body} particle
  6973. */
  6974. SPHSystem.prototype.remove = function(particle){
  6975. var idx = this.particles.indexOf(particle);
  6976. if(idx !== -1){
  6977. this.particles.splice(idx,1);
  6978. if(this.neighbors.length > this.particles.length){
  6979. this.neighbors.pop();
  6980. }
  6981. }
  6982. };
  6983. /**
  6984. * Get neighbors within smoothing volume, save in the array neighbors
  6985. * @method getNeighbors
  6986. * @param {Body} particle
  6987. * @param {Array} neighbors
  6988. */
  6989. var SPHSystem_getNeighbors_dist = new Vec3();
  6990. SPHSystem.prototype.getNeighbors = function(particle,neighbors){
  6991. var N = this.particles.length,
  6992. id = particle.id,
  6993. R2 = this.smoothingRadius * this.smoothingRadius,
  6994. dist = SPHSystem_getNeighbors_dist;
  6995. for(var i=0; i!==N; i++){
  6996. var p = this.particles[i];
  6997. p.position.vsub(particle.position,dist);
  6998. if(id!==p.id && dist.norm2() < R2){
  6999. neighbors.push(p);
  7000. }
  7001. }
  7002. };
  7003. // Temp vectors for calculation
  7004. var SPHSystem_update_dist = new Vec3(),
  7005. SPHSystem_update_a_pressure = new Vec3(),
  7006. SPHSystem_update_a_visc = new Vec3(),
  7007. SPHSystem_update_gradW = new Vec3(),
  7008. SPHSystem_update_r_vec = new Vec3(),
  7009. SPHSystem_update_u = new Vec3(); // Relative velocity
  7010. SPHSystem.prototype.update = function(){
  7011. var N = this.particles.length,
  7012. dist = SPHSystem_update_dist,
  7013. cs = this.speedOfSound,
  7014. eps = this.eps;
  7015. for(var i=0; i!==N; i++){
  7016. var p = this.particles[i]; // Current particle
  7017. var neighbors = this.neighbors[i];
  7018. // Get neighbors
  7019. neighbors.length = 0;
  7020. this.getNeighbors(p,neighbors);
  7021. neighbors.push(this.particles[i]); // Add current too
  7022. var numNeighbors = neighbors.length;
  7023. // Accumulate density for the particle
  7024. var sum = 0.0;
  7025. for(var j=0; j!==numNeighbors; j++){
  7026. //printf("Current particle has position %f %f %f\n",objects[id].pos.x(),objects[id].pos.y(),objects[id].pos.z());
  7027. p.position.vsub(neighbors[j].position, dist);
  7028. var len = dist.norm();
  7029. var weight = this.w(len);
  7030. sum += neighbors[j].mass * weight;
  7031. }
  7032. // Save
  7033. this.densities[i] = sum;
  7034. this.pressures[i] = cs * cs * (this.densities[i] - this.density);
  7035. }
  7036. // Add forces
  7037. // Sum to these accelerations
  7038. var a_pressure= SPHSystem_update_a_pressure;
  7039. var a_visc = SPHSystem_update_a_visc;
  7040. var gradW = SPHSystem_update_gradW;
  7041. var r_vec = SPHSystem_update_r_vec;
  7042. var u = SPHSystem_update_u;
  7043. for(var i=0; i!==N; i++){
  7044. var particle = this.particles[i];
  7045. a_pressure.set(0,0,0);
  7046. a_visc.set(0,0,0);
  7047. // Init vars
  7048. var Pij;
  7049. var nabla;
  7050. var Vij;
  7051. // Sum up for all other neighbors
  7052. var neighbors = this.neighbors[i];
  7053. var numNeighbors = neighbors.length;
  7054. //printf("Neighbors: ");
  7055. for(var j=0; j!==numNeighbors; j++){
  7056. var neighbor = neighbors[j];
  7057. //printf("%d ",nj);
  7058. // Get r once for all..
  7059. particle.position.vsub(neighbor.position,r_vec);
  7060. var r = r_vec.norm();
  7061. // Pressure contribution
  7062. Pij = -neighbor.mass * (this.pressures[i] / (this.densities[i]*this.densities[i] + eps) + this.pressures[j] / (this.densities[j]*this.densities[j] + eps));
  7063. this.gradw(r_vec, gradW);
  7064. // Add to pressure acceleration
  7065. gradW.mult(Pij , gradW);
  7066. a_pressure.vadd(gradW, a_pressure);
  7067. // Viscosity contribution
  7068. neighbor.velocity.vsub(particle.velocity, u);
  7069. u.mult( 1.0 / (0.0001+this.densities[i] * this.densities[j]) * this.viscosity * neighbor.mass , u );
  7070. nabla = this.nablaw(r);
  7071. u.mult(nabla,u);
  7072. // Add to viscosity acceleration
  7073. a_visc.vadd( u, a_visc );
  7074. }
  7075. // Calculate force
  7076. a_visc.mult(particle.mass, a_visc);
  7077. a_pressure.mult(particle.mass, a_pressure);
  7078. // Add force to particles
  7079. particle.force.vadd(a_visc, particle.force);
  7080. particle.force.vadd(a_pressure, particle.force);
  7081. }
  7082. };
  7083. // Calculate the weight using the W(r) weightfunction
  7084. SPHSystem.prototype.w = function(r){
  7085. // 315
  7086. var h = this.smoothingRadius;
  7087. return 315.0/(64.0*Math.PI*Math.pow(h,9)) * Math.pow(h*h-r*r,3);
  7088. };
  7089. // calculate gradient of the weight function
  7090. SPHSystem.prototype.gradw = function(rVec,resultVec){
  7091. var r = rVec.norm(),
  7092. h = this.smoothingRadius;
  7093. rVec.mult(945.0/(32.0*Math.PI*Math.pow(h,9)) * Math.pow((h*h-r*r),2) , resultVec);
  7094. };
  7095. // Calculate nabla(W)
  7096. SPHSystem.prototype.nablaw = function(r){
  7097. var h = this.smoothingRadius;
  7098. var nabla = 945.0/(32.0*Math.PI*Math.pow(h,9)) * (h*h-r*r)*(7*r*r - 3*h*h);
  7099. return nabla;
  7100. };
  7101. },{"../material/Material":38,"../math/Quaternion":41,"../math/Vec3":43,"../objects/Body":44,"../shapes/Particle":54,"../shapes/Shape":56}],48:[function(require,module,exports){
  7102. var Vec3 = require('../math/Vec3');
  7103. module.exports = Spring;
  7104. /**
  7105. * A spring, connecting two bodies.
  7106. *
  7107. * @class Spring
  7108. * @constructor
  7109. * @param {Body} bodyA
  7110. * @param {Body} bodyB
  7111. * @param {Object} [options]
  7112. * @param {number} [options.restLength] A number > 0. Default: 1
  7113. * @param {number} [options.stiffness] A number >= 0. Default: 100
  7114. * @param {number} [options.damping] A number >= 0. Default: 1
  7115. * @param {Vec3} [options.worldAnchorA] Where to hook the spring to body A, in world coordinates.
  7116. * @param {Vec3} [options.worldAnchorB]
  7117. * @param {Vec3} [options.localAnchorA] Where to hook the spring to body A, in local body coordinates.
  7118. * @param {Vec3} [options.localAnchorB]
  7119. */
  7120. function Spring(bodyA,bodyB,options){
  7121. options = options || {};
  7122. /**
  7123. * Rest length of the spring.
  7124. * @property restLength
  7125. * @type {number}
  7126. */
  7127. this.restLength = typeof(options.restLength) === "number" ? options.restLength : 1;
  7128. /**
  7129. * Stiffness of the spring.
  7130. * @property stiffness
  7131. * @type {number}
  7132. */
  7133. this.stiffness = options.stiffness || 100;
  7134. /**
  7135. * Damping of the spring.
  7136. * @property damping
  7137. * @type {number}
  7138. */
  7139. this.damping = options.damping || 1;
  7140. /**
  7141. * First connected body.
  7142. * @property bodyA
  7143. * @type {Body}
  7144. */
  7145. this.bodyA = bodyA;
  7146. /**
  7147. * Second connected body.
  7148. * @property bodyB
  7149. * @type {Body}
  7150. */
  7151. this.bodyB = bodyB;
  7152. /**
  7153. * Anchor for bodyA in local bodyA coordinates.
  7154. * @property localAnchorA
  7155. * @type {Vec3}
  7156. */
  7157. this.localAnchorA = new Vec3();
  7158. /**
  7159. * Anchor for bodyB in local bodyB coordinates.
  7160. * @property localAnchorB
  7161. * @type {Vec3}
  7162. */
  7163. this.localAnchorB = new Vec3();
  7164. if(options.localAnchorA){
  7165. this.localAnchorA.copy(options.localAnchorA);
  7166. }
  7167. if(options.localAnchorB){
  7168. this.localAnchorB.copy(options.localAnchorB);
  7169. }
  7170. if(options.worldAnchorA){
  7171. this.setWorldAnchorA(options.worldAnchorA);
  7172. }
  7173. if(options.worldAnchorB){
  7174. this.setWorldAnchorB(options.worldAnchorB);
  7175. }
  7176. }
  7177. /**
  7178. * Set the anchor point on body A, using world coordinates.
  7179. * @method setWorldAnchorA
  7180. * @param {Vec3} worldAnchorA
  7181. */
  7182. Spring.prototype.setWorldAnchorA = function(worldAnchorA){
  7183. this.bodyA.pointToLocalFrame(worldAnchorA,this.localAnchorA);
  7184. };
  7185. /**
  7186. * Set the anchor point on body B, using world coordinates.
  7187. * @method setWorldAnchorB
  7188. * @param {Vec3} worldAnchorB
  7189. */
  7190. Spring.prototype.setWorldAnchorB = function(worldAnchorB){
  7191. this.bodyB.pointToLocalFrame(worldAnchorB,this.localAnchorB);
  7192. };
  7193. /**
  7194. * Get the anchor point on body A, in world coordinates.
  7195. * @method getWorldAnchorA
  7196. * @param {Vec3} result The vector to store the result in.
  7197. */
  7198. Spring.prototype.getWorldAnchorA = function(result){
  7199. this.bodyA.pointToWorldFrame(this.localAnchorA,result);
  7200. };
  7201. /**
  7202. * Get the anchor point on body B, in world coordinates.
  7203. * @method getWorldAnchorB
  7204. * @param {Vec3} result The vector to store the result in.
  7205. */
  7206. Spring.prototype.getWorldAnchorB = function(result){
  7207. this.bodyB.pointToWorldFrame(this.localAnchorB,result);
  7208. };
  7209. var applyForce_r = new Vec3(),
  7210. applyForce_r_unit = new Vec3(),
  7211. applyForce_u = new Vec3(),
  7212. applyForce_f = new Vec3(),
  7213. applyForce_worldAnchorA = new Vec3(),
  7214. applyForce_worldAnchorB = new Vec3(),
  7215. applyForce_ri = new Vec3(),
  7216. applyForce_rj = new Vec3(),
  7217. applyForce_ri_x_f = new Vec3(),
  7218. applyForce_rj_x_f = new Vec3(),
  7219. applyForce_tmp = new Vec3();
  7220. /**
  7221. * Apply the spring force to the connected bodies.
  7222. * @method applyForce
  7223. */
  7224. Spring.prototype.applyForce = function(){
  7225. var k = this.stiffness,
  7226. d = this.damping,
  7227. l = this.restLength,
  7228. bodyA = this.bodyA,
  7229. bodyB = this.bodyB,
  7230. r = applyForce_r,
  7231. r_unit = applyForce_r_unit,
  7232. u = applyForce_u,
  7233. f = applyForce_f,
  7234. tmp = applyForce_tmp;
  7235. var worldAnchorA = applyForce_worldAnchorA,
  7236. worldAnchorB = applyForce_worldAnchorB,
  7237. ri = applyForce_ri,
  7238. rj = applyForce_rj,
  7239. ri_x_f = applyForce_ri_x_f,
  7240. rj_x_f = applyForce_rj_x_f;
  7241. // Get world anchors
  7242. this.getWorldAnchorA(worldAnchorA);
  7243. this.getWorldAnchorB(worldAnchorB);
  7244. // Get offset points
  7245. worldAnchorA.vsub(bodyA.position,ri);
  7246. worldAnchorB.vsub(bodyB.position,rj);
  7247. // Compute distance vector between world anchor points
  7248. worldAnchorB.vsub(worldAnchorA,r);
  7249. var rlen = r.norm();
  7250. r_unit.copy(r);
  7251. r_unit.normalize();
  7252. // Compute relative velocity of the anchor points, u
  7253. bodyB.velocity.vsub(bodyA.velocity,u);
  7254. // Add rotational velocity
  7255. bodyB.angularVelocity.cross(rj,tmp);
  7256. u.vadd(tmp,u);
  7257. bodyA.angularVelocity.cross(ri,tmp);
  7258. u.vsub(tmp,u);
  7259. // F = - k * ( x - L ) - D * ( u )
  7260. r_unit.mult(-k*(rlen-l) - d*u.dot(r_unit), f);
  7261. // Add forces to bodies
  7262. bodyA.force.vsub(f,bodyA.force);
  7263. bodyB.force.vadd(f,bodyB.force);
  7264. // Angular force
  7265. ri.cross(f,ri_x_f);
  7266. rj.cross(f,rj_x_f);
  7267. bodyA.torque.vsub(ri_x_f,bodyA.torque);
  7268. bodyB.torque.vadd(rj_x_f,bodyB.torque);
  7269. };
  7270. },{"../math/Vec3":43}],49:[function(require,module,exports){
  7271. var Vec3 = require('../math/Vec3');
  7272. var Transform = require('../math/Transform');
  7273. var RaycastResult = require('../collision/RaycastResult');
  7274. var Utils = require('../utils/Utils');
  7275. module.exports = WheelInfo;
  7276. /**
  7277. * @class WheelInfo
  7278. * @constructor
  7279. * @param {Object} [options]
  7280. *
  7281. * @param {Vec3} [options.chassisConnectionPointLocal]
  7282. * @param {Vec3} [options.chassisConnectionPointWorld]
  7283. * @param {Vec3} [options.directionLocal]
  7284. * @param {Vec3} [options.directionWorld]
  7285. * @param {Vec3} [options.axleLocal]
  7286. * @param {Vec3} [options.axleWorld]
  7287. * @param {number} [options.suspensionRestLength=1]
  7288. * @param {number} [options.suspensionMaxLength=2]
  7289. * @param {number} [options.radius=1]
  7290. * @param {number} [options.suspensionStiffness=100]
  7291. * @param {number} [options.dampingCompression=10]
  7292. * @param {number} [options.dampingRelaxation=10]
  7293. * @param {number} [options.frictionSlip=10000]
  7294. * @param {number} [options.steering=0]
  7295. * @param {number} [options.rotation=0]
  7296. * @param {number} [options.deltaRotation=0]
  7297. * @param {number} [options.rollInfluence=0.01]
  7298. * @param {number} [options.maxSuspensionForce]
  7299. * @param {boolean} [options.isFrontWheel=true]
  7300. * @param {number} [options.clippedInvContactDotSuspension=1]
  7301. * @param {number} [options.suspensionRelativeVelocity=0]
  7302. * @param {number} [options.suspensionForce=0]
  7303. * @param {number} [options.skidInfo=0]
  7304. * @param {number} [options.suspensionLength=0]
  7305. * @param {number} [options.maxSuspensionTravel=1]
  7306. * @param {boolean} [options.useCustomSlidingRotationalSpeed=false]
  7307. * @param {number} [options.customSlidingRotationalSpeed=-0.1]
  7308. */
  7309. function WheelInfo(options){
  7310. options = Utils.defaults(options, {
  7311. chassisConnectionPointLocal: new Vec3(),
  7312. chassisConnectionPointWorld: new Vec3(),
  7313. directionLocal: new Vec3(),
  7314. directionWorld: new Vec3(),
  7315. axleLocal: new Vec3(),
  7316. axleWorld: new Vec3(),
  7317. suspensionRestLength: 1,
  7318. suspensionMaxLength: 2,
  7319. radius: 1,
  7320. suspensionStiffness: 100,
  7321. dampingCompression: 10,
  7322. dampingRelaxation: 10,
  7323. frictionSlip: 10000,
  7324. steering: 0,
  7325. rotation: 0,
  7326. deltaRotation: 0,
  7327. rollInfluence: 0.01,
  7328. maxSuspensionForce: Number.MAX_VALUE,
  7329. isFrontWheel: true,
  7330. clippedInvContactDotSuspension: 1,
  7331. suspensionRelativeVelocity: 0,
  7332. suspensionForce: 0,
  7333. skidInfo: 0,
  7334. suspensionLength: 0,
  7335. maxSuspensionTravel: 1,
  7336. useCustomSlidingRotationalSpeed: false,
  7337. customSlidingRotationalSpeed: -0.1
  7338. });
  7339. /**
  7340. * Max travel distance of the suspension, in meters.
  7341. * @property {number} maxSuspensionTravel
  7342. */
  7343. this.maxSuspensionTravel = options.maxSuspensionTravel;
  7344. /**
  7345. * Speed to apply to the wheel rotation when the wheel is sliding.
  7346. * @property {number} customSlidingRotationalSpeed
  7347. */
  7348. this.customSlidingRotationalSpeed = options.customSlidingRotationalSpeed;
  7349. /**
  7350. * If the customSlidingRotationalSpeed should be used.
  7351. * @property {Boolean} useCustomSlidingRotationalSpeed
  7352. */
  7353. this.useCustomSlidingRotationalSpeed = options.useCustomSlidingRotationalSpeed;
  7354. /**
  7355. * @property {Boolean} sliding
  7356. */
  7357. this.sliding = false;
  7358. /**
  7359. * Connection point, defined locally in the chassis body frame.
  7360. * @property {Vec3} chassisConnectionPointLocal
  7361. */
  7362. this.chassisConnectionPointLocal = options.chassisConnectionPointLocal.clone();
  7363. /**
  7364. * @property {Vec3} chassisConnectionPointWorld
  7365. */
  7366. this.chassisConnectionPointWorld = options.chassisConnectionPointWorld.clone();
  7367. /**
  7368. * @property {Vec3} directionLocal
  7369. */
  7370. this.directionLocal = options.directionLocal.clone();
  7371. /**
  7372. * @property {Vec3} directionWorld
  7373. */
  7374. this.directionWorld = options.directionWorld.clone();
  7375. /**
  7376. * @property {Vec3} axleLocal
  7377. */
  7378. this.axleLocal = options.axleLocal.clone();
  7379. /**
  7380. * @property {Vec3} axleWorld
  7381. */
  7382. this.axleWorld = options.axleWorld.clone();
  7383. /**
  7384. * @property {number} suspensionRestLength
  7385. */
  7386. this.suspensionRestLength = options.suspensionRestLength;
  7387. /**
  7388. * @property {number} suspensionMaxLength
  7389. */
  7390. this.suspensionMaxLength = options.suspensionMaxLength;
  7391. /**
  7392. * @property {number} radius
  7393. */
  7394. this.radius = options.radius;
  7395. /**
  7396. * @property {number} suspensionStiffness
  7397. */
  7398. this.suspensionStiffness = options.suspensionStiffness;
  7399. /**
  7400. * @property {number} dampingCompression
  7401. */
  7402. this.dampingCompression = options.dampingCompression;
  7403. /**
  7404. * @property {number} dampingRelaxation
  7405. */
  7406. this.dampingRelaxation = options.dampingRelaxation;
  7407. /**
  7408. * @property {number} frictionSlip
  7409. */
  7410. this.frictionSlip = options.frictionSlip;
  7411. /**
  7412. * @property {number} steering
  7413. */
  7414. this.steering = 0;
  7415. /**
  7416. * Rotation value, in radians.
  7417. * @property {number} rotation
  7418. */
  7419. this.rotation = 0;
  7420. /**
  7421. * @property {number} deltaRotation
  7422. */
  7423. this.deltaRotation = 0;
  7424. /**
  7425. * @property {number} rollInfluence
  7426. */
  7427. this.rollInfluence = options.rollInfluence;
  7428. /**
  7429. * @property {number} maxSuspensionForce
  7430. */
  7431. this.maxSuspensionForce = options.maxSuspensionForce;
  7432. /**
  7433. * @property {number} engineForce
  7434. */
  7435. this.engineForce = 0;
  7436. /**
  7437. * @property {number} brake
  7438. */
  7439. this.brake = 0;
  7440. /**
  7441. * @property {number} isFrontWheel
  7442. */
  7443. this.isFrontWheel = options.isFrontWheel;
  7444. /**
  7445. * @property {number} clippedInvContactDotSuspension
  7446. */
  7447. this.clippedInvContactDotSuspension = 1;
  7448. /**
  7449. * @property {number} suspensionRelativeVelocity
  7450. */
  7451. this.suspensionRelativeVelocity = 0;
  7452. /**
  7453. * @property {number} suspensionForce
  7454. */
  7455. this.suspensionForce = 0;
  7456. /**
  7457. * @property {number} skidInfo
  7458. */
  7459. this.skidInfo = 0;
  7460. /**
  7461. * @property {number} suspensionLength
  7462. */
  7463. this.suspensionLength = 0;
  7464. /**
  7465. * @property {number} sideImpulse
  7466. */
  7467. this.sideImpulse = 0;
  7468. /**
  7469. * @property {number} forwardImpulse
  7470. */
  7471. this.forwardImpulse = 0;
  7472. /**
  7473. * The result from raycasting
  7474. * @property {RaycastResult} raycastResult
  7475. */
  7476. this.raycastResult = new RaycastResult();
  7477. /**
  7478. * Wheel world transform
  7479. * @property {Transform} worldTransform
  7480. */
  7481. this.worldTransform = new Transform();
  7482. /**
  7483. * @property {boolean} isInContact
  7484. */
  7485. this.isInContact = false;
  7486. }
  7487. var chassis_velocity_at_contactPoint = new Vec3();
  7488. var relpos = new Vec3();
  7489. var chassis_velocity_at_contactPoint = new Vec3();
  7490. WheelInfo.prototype.updateWheel = function(chassis){
  7491. var raycastResult = this.raycastResult;
  7492. if (this.isInContact){
  7493. var project= raycastResult.hitNormalWorld.dot(raycastResult.directionWorld);
  7494. raycastResult.hitPointWorld.vsub(chassis.position, relpos);
  7495. chassis.getVelocityAtWorldPoint(relpos, chassis_velocity_at_contactPoint);
  7496. var projVel = raycastResult.hitNormalWorld.dot( chassis_velocity_at_contactPoint );
  7497. if (project >= -0.1) {
  7498. this.suspensionRelativeVelocity = 0.0;
  7499. this.clippedInvContactDotSuspension = 1.0 / 0.1;
  7500. } else {
  7501. var inv = -1 / project;
  7502. this.suspensionRelativeVelocity = projVel * inv;
  7503. this.clippedInvContactDotSuspension = inv;
  7504. }
  7505. } else {
  7506. // Not in contact : position wheel in a nice (rest length) position
  7507. raycastResult.suspensionLength = this.suspensionRestLength;
  7508. this.suspensionRelativeVelocity = 0.0;
  7509. raycastResult.directionWorld.scale(-1, raycastResult.hitNormalWorld);
  7510. this.clippedInvContactDotSuspension = 1.0;
  7511. }
  7512. };
  7513. },{"../collision/RaycastResult":23,"../math/Transform":42,"../math/Vec3":43,"../utils/Utils":66}],50:[function(require,module,exports){
  7514. module.exports = Box;
  7515. var Shape = require('./Shape');
  7516. var Vec3 = require('../math/Vec3');
  7517. var ConvexPolyhedron = require('./ConvexPolyhedron');
  7518. /**
  7519. * A 3d box shape.
  7520. * @class Box
  7521. * @constructor
  7522. * @param {Vec3} halfExtents
  7523. * @author schteppe
  7524. * @extends Shape
  7525. */
  7526. function Box(halfExtents){
  7527. Shape.call(this);
  7528. this.type = Shape.types.BOX;
  7529. /**
  7530. * @property halfExtents
  7531. * @type {Vec3}
  7532. */
  7533. this.halfExtents = halfExtents;
  7534. /**
  7535. * Used by the contact generator to make contacts with other convex polyhedra for example
  7536. * @property convexPolyhedronRepresentation
  7537. * @type {ConvexPolyhedron}
  7538. */
  7539. this.convexPolyhedronRepresentation = null;
  7540. this.updateConvexPolyhedronRepresentation();
  7541. this.updateBoundingSphereRadius();
  7542. }
  7543. Box.prototype = new Shape();
  7544. Box.prototype.constructor = Box;
  7545. /**
  7546. * Updates the local convex polyhedron representation used for some collisions.
  7547. * @method updateConvexPolyhedronRepresentation
  7548. */
  7549. Box.prototype.updateConvexPolyhedronRepresentation = function(){
  7550. var sx = this.halfExtents.x;
  7551. var sy = this.halfExtents.y;
  7552. var sz = this.halfExtents.z;
  7553. var V = Vec3;
  7554. var vertices = [
  7555. new V(-sx,-sy,-sz),
  7556. new V( sx,-sy,-sz),
  7557. new V( sx, sy,-sz),
  7558. new V(-sx, sy,-sz),
  7559. new V(-sx,-sy, sz),
  7560. new V( sx,-sy, sz),
  7561. new V( sx, sy, sz),
  7562. new V(-sx, sy, sz)
  7563. ];
  7564. var indices = [
  7565. [3,2,1,0], // -z
  7566. [4,5,6,7], // +z
  7567. [5,4,0,1], // -y
  7568. [2,3,7,6], // +y
  7569. [0,4,7,3], // -x
  7570. [1,2,6,5], // +x
  7571. ];
  7572. var axes = [
  7573. new V(0, 0, 1),
  7574. new V(0, 1, 0),
  7575. new V(1, 0, 0)
  7576. ];
  7577. var h = new ConvexPolyhedron(vertices, indices);
  7578. this.convexPolyhedronRepresentation = h;
  7579. h.material = this.material;
  7580. };
  7581. /**
  7582. * @method calculateLocalInertia
  7583. * @param {Number} mass
  7584. * @param {Vec3} target
  7585. * @return {Vec3}
  7586. */
  7587. Box.prototype.calculateLocalInertia = function(mass,target){
  7588. target = target || new Vec3();
  7589. Box.calculateInertia(this.halfExtents, mass, target);
  7590. return target;
  7591. };
  7592. Box.calculateInertia = function(halfExtents,mass,target){
  7593. var e = halfExtents;
  7594. target.x = 1.0 / 12.0 * mass * ( 2*e.y*2*e.y + 2*e.z*2*e.z );
  7595. target.y = 1.0 / 12.0 * mass * ( 2*e.x*2*e.x + 2*e.z*2*e.z );
  7596. target.z = 1.0 / 12.0 * mass * ( 2*e.y*2*e.y + 2*e.x*2*e.x );
  7597. };
  7598. /**
  7599. * Get the box 6 side normals
  7600. * @method getSideNormals
  7601. * @param {array} sixTargetVectors An array of 6 vectors, to store the resulting side normals in.
  7602. * @param {Quaternion} quat Orientation to apply to the normal vectors. If not provided, the vectors will be in respect to the local frame.
  7603. * @return {array}
  7604. */
  7605. Box.prototype.getSideNormals = function(sixTargetVectors,quat){
  7606. var sides = sixTargetVectors;
  7607. var ex = this.halfExtents;
  7608. sides[0].set( ex.x, 0, 0);
  7609. sides[1].set( 0, ex.y, 0);
  7610. sides[2].set( 0, 0, ex.z);
  7611. sides[3].set( -ex.x, 0, 0);
  7612. sides[4].set( 0, -ex.y, 0);
  7613. sides[5].set( 0, 0, -ex.z);
  7614. if(quat!==undefined){
  7615. for(var i=0; i!==sides.length; i++){
  7616. quat.vmult(sides[i],sides[i]);
  7617. }
  7618. }
  7619. return sides;
  7620. };
  7621. Box.prototype.volume = function(){
  7622. return 8.0 * this.halfExtents.x * this.halfExtents.y * this.halfExtents.z;
  7623. };
  7624. Box.prototype.updateBoundingSphereRadius = function(){
  7625. this.boundingSphereRadius = this.halfExtents.norm();
  7626. };
  7627. var worldCornerTempPos = new Vec3();
  7628. var worldCornerTempNeg = new Vec3();
  7629. Box.prototype.forEachWorldCorner = function(pos,quat,callback){
  7630. var e = this.halfExtents;
  7631. var corners = [[ e.x, e.y, e.z],
  7632. [ -e.x, e.y, e.z],
  7633. [ -e.x, -e.y, e.z],
  7634. [ -e.x, -e.y, -e.z],
  7635. [ e.x, -e.y, -e.z],
  7636. [ e.x, e.y, -e.z],
  7637. [ -e.x, e.y, -e.z],
  7638. [ e.x, -e.y, e.z]];
  7639. for(var i=0; i<corners.length; i++){
  7640. worldCornerTempPos.set(corners[i][0],corners[i][1],corners[i][2]);
  7641. quat.vmult(worldCornerTempPos,worldCornerTempPos);
  7642. pos.vadd(worldCornerTempPos,worldCornerTempPos);
  7643. callback(worldCornerTempPos.x,
  7644. worldCornerTempPos.y,
  7645. worldCornerTempPos.z);
  7646. }
  7647. };
  7648. var worldCornersTemp = [
  7649. new Vec3(),
  7650. new Vec3(),
  7651. new Vec3(),
  7652. new Vec3(),
  7653. new Vec3(),
  7654. new Vec3(),
  7655. new Vec3(),
  7656. new Vec3()
  7657. ];
  7658. Box.prototype.calculateWorldAABB = function(pos,quat,min,max){
  7659. var e = this.halfExtents;
  7660. worldCornersTemp[0].set(e.x, e.y, e.z);
  7661. worldCornersTemp[1].set(-e.x, e.y, e.z);
  7662. worldCornersTemp[2].set(-e.x, -e.y, e.z);
  7663. worldCornersTemp[3].set(-e.x, -e.y, -e.z);
  7664. worldCornersTemp[4].set(e.x, -e.y, -e.z);
  7665. worldCornersTemp[5].set(e.x, e.y, -e.z);
  7666. worldCornersTemp[6].set(-e.x, e.y, -e.z);
  7667. worldCornersTemp[7].set(e.x, -e.y, e.z);
  7668. var wc = worldCornersTemp[0];
  7669. quat.vmult(wc, wc);
  7670. pos.vadd(wc, wc);
  7671. max.copy(wc);
  7672. min.copy(wc);
  7673. for(var i=1; i<8; i++){
  7674. var wc = worldCornersTemp[i];
  7675. quat.vmult(wc, wc);
  7676. pos.vadd(wc, wc);
  7677. var x = wc.x;
  7678. var y = wc.y;
  7679. var z = wc.z;
  7680. if(x > max.x){
  7681. max.x = x;
  7682. }
  7683. if(y > max.y){
  7684. max.y = y;
  7685. }
  7686. if(z > max.z){
  7687. max.z = z;
  7688. }
  7689. if(x < min.x){
  7690. min.x = x;
  7691. }
  7692. if(y < min.y){
  7693. min.y = y;
  7694. }
  7695. if(z < min.z){
  7696. min.z = z;
  7697. }
  7698. }
  7699. // Get each axis max
  7700. // min.set(Infinity,Infinity,Infinity);
  7701. // max.set(-Infinity,-Infinity,-Infinity);
  7702. // this.forEachWorldCorner(pos,quat,function(x,y,z){
  7703. // if(x > max.x){
  7704. // max.x = x;
  7705. // }
  7706. // if(y > max.y){
  7707. // max.y = y;
  7708. // }
  7709. // if(z > max.z){
  7710. // max.z = z;
  7711. // }
  7712. // if(x < min.x){
  7713. // min.x = x;
  7714. // }
  7715. // if(y < min.y){
  7716. // min.y = y;
  7717. // }
  7718. // if(z < min.z){
  7719. // min.z = z;
  7720. // }
  7721. // });
  7722. };
  7723. },{"../math/Vec3":43,"./ConvexPolyhedron":51,"./Shape":56}],51:[function(require,module,exports){
  7724. module.exports = ConvexPolyhedron;
  7725. var Shape = require('./Shape');
  7726. var Vec3 = require('../math/Vec3');
  7727. var Quaternion = require('../math/Quaternion');
  7728. var Transform = require('../math/Transform');
  7729. /**
  7730. * A set of polygons describing a convex shape.
  7731. * @class ConvexPolyhedron
  7732. * @constructor
  7733. * @extends Shape
  7734. * @description The shape MUST be convex for the code to work properly. No polygons may be coplanar (contained
  7735. * in the same 3D plane), instead these should be merged into one polygon.
  7736. *
  7737. * @param {array} points An array of Vec3's
  7738. * @param {array} faces Array of integer arrays, describing which vertices that is included in each face.
  7739. *
  7740. * @author qiao / https://github.com/qiao (original author, see https://github.com/qiao/three.js/commit/85026f0c769e4000148a67d45a9e9b9c5108836f)
  7741. * @author schteppe / https://github.com/schteppe
  7742. * @see http://www.altdevblogaday.com/2011/05/13/contact-generation-between-3d-convex-meshes/
  7743. * @see http://bullet.googlecode.com/svn/trunk/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
  7744. *
  7745. * @todo Move the clipping functions to ContactGenerator?
  7746. * @todo Automatically merge coplanar polygons in constructor.
  7747. */
  7748. function ConvexPolyhedron(points, faces, uniqueAxes) {
  7749. var that = this;
  7750. Shape.call(this);
  7751. this.type = Shape.types.CONVEXPOLYHEDRON;
  7752. /**
  7753. * Array of Vec3
  7754. * @property vertices
  7755. * @type {Array}
  7756. */
  7757. this.vertices = points||[];
  7758. this.worldVertices = []; // World transformed version of .vertices
  7759. this.worldVerticesNeedsUpdate = true;
  7760. /**
  7761. * Array of integer arrays, indicating which vertices each face consists of
  7762. * @property faces
  7763. * @type {Array}
  7764. */
  7765. this.faces = faces||[];
  7766. /**
  7767. * Array of Vec3
  7768. * @property faceNormals
  7769. * @type {Array}
  7770. */
  7771. this.faceNormals = [];
  7772. this.computeNormals();
  7773. this.worldFaceNormalsNeedsUpdate = true;
  7774. this.worldFaceNormals = []; // World transformed version of .faceNormals
  7775. /**
  7776. * Array of Vec3
  7777. * @property uniqueEdges
  7778. * @type {Array}
  7779. */
  7780. this.uniqueEdges = [];
  7781. /**
  7782. * If given, these locally defined, normalized axes are the only ones being checked when doing separating axis check.
  7783. * @property {Array} uniqueAxes
  7784. */
  7785. this.uniqueAxes = uniqueAxes ? uniqueAxes.slice() : null;
  7786. this.computeEdges();
  7787. this.updateBoundingSphereRadius();
  7788. }
  7789. ConvexPolyhedron.prototype = new Shape();
  7790. ConvexPolyhedron.prototype.constructor = ConvexPolyhedron;
  7791. var computeEdges_tmpEdge = new Vec3();
  7792. /**
  7793. * Computes uniqueEdges
  7794. * @method computeEdges
  7795. */
  7796. ConvexPolyhedron.prototype.computeEdges = function(){
  7797. var faces = this.faces;
  7798. var vertices = this.vertices;
  7799. var nv = vertices.length;
  7800. var edges = this.uniqueEdges;
  7801. edges.length = 0;
  7802. var edge = computeEdges_tmpEdge;
  7803. for(var i=0; i !== faces.length; i++){
  7804. var face = faces[i];
  7805. var numVertices = face.length;
  7806. for(var j = 0; j !== numVertices; j++){
  7807. var k = ( j+1 ) % numVertices;
  7808. vertices[face[j]].vsub(vertices[face[k]], edge);
  7809. edge.normalize();
  7810. var found = false;
  7811. for(var p=0; p !== edges.length; p++){
  7812. if (edges[p].almostEquals(edge) || edges[p].almostEquals(edge)){
  7813. found = true;
  7814. break;
  7815. }
  7816. }
  7817. if (!found){
  7818. edges.push(edge.clone());
  7819. }
  7820. }
  7821. }
  7822. };
  7823. /**
  7824. * Compute the normals of the faces. Will reuse existing Vec3 objects in the .faceNormals array if they exist.
  7825. * @method computeNormals
  7826. */
  7827. ConvexPolyhedron.prototype.computeNormals = function(){
  7828. this.faceNormals.length = this.faces.length;
  7829. // Generate normals
  7830. for(var i=0; i<this.faces.length; i++){
  7831. // Check so all vertices exists for this face
  7832. for(var j=0; j<this.faces[i].length; j++){
  7833. if(!this.vertices[this.faces[i][j]]){
  7834. throw new Error("Vertex "+this.faces[i][j]+" not found!");
  7835. }
  7836. }
  7837. var n = this.faceNormals[i] || new Vec3();
  7838. this.getFaceNormal(i,n);
  7839. n.negate(n);
  7840. this.faceNormals[i] = n;
  7841. var vertex = this.vertices[this.faces[i][0]];
  7842. if(n.dot(vertex) < 0){
  7843. 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.");
  7844. for(var j=0; j<this.faces[i].length; j++){
  7845. console.warn(".vertices["+this.faces[i][j]+"] = Vec3("+this.vertices[this.faces[i][j]].toString()+")");
  7846. }
  7847. }
  7848. }
  7849. };
  7850. /**
  7851. * Get face normal given 3 vertices
  7852. * @static
  7853. * @method getFaceNormal
  7854. * @param {Vec3} va
  7855. * @param {Vec3} vb
  7856. * @param {Vec3} vc
  7857. * @param {Vec3} target
  7858. */
  7859. var cb = new Vec3();
  7860. var ab = new Vec3();
  7861. ConvexPolyhedron.computeNormal = function ( va, vb, vc, target ) {
  7862. vb.vsub(va,ab);
  7863. vc.vsub(vb,cb);
  7864. cb.cross(ab,target);
  7865. if ( !target.isZero() ) {
  7866. target.normalize();
  7867. }
  7868. };
  7869. /**
  7870. * Compute the normal of a face from its vertices
  7871. * @method getFaceNormal
  7872. * @param {Number} i
  7873. * @param {Vec3} target
  7874. */
  7875. ConvexPolyhedron.prototype.getFaceNormal = function(i,target){
  7876. var f = this.faces[i];
  7877. var va = this.vertices[f[0]];
  7878. var vb = this.vertices[f[1]];
  7879. var vc = this.vertices[f[2]];
  7880. return ConvexPolyhedron.computeNormal(va,vb,vc,target);
  7881. };
  7882. /**
  7883. * @method clipAgainstHull
  7884. * @param {Vec3} posA
  7885. * @param {Quaternion} quatA
  7886. * @param {ConvexPolyhedron} hullB
  7887. * @param {Vec3} posB
  7888. * @param {Quaternion} quatB
  7889. * @param {Vec3} separatingNormal
  7890. * @param {Number} minDist Clamp distance
  7891. * @param {Number} maxDist
  7892. * @param {array} result The an array of contact point objects, see clipFaceAgainstHull
  7893. * @see http://bullet.googlecode.com/svn/trunk/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
  7894. */
  7895. var cah_WorldNormal = new Vec3();
  7896. ConvexPolyhedron.prototype.clipAgainstHull = function(posA,quatA,hullB,posB,quatB,separatingNormal,minDist,maxDist,result){
  7897. var WorldNormal = cah_WorldNormal;
  7898. var hullA = this;
  7899. var curMaxDist = maxDist;
  7900. var closestFaceB = -1;
  7901. var dmax = -Number.MAX_VALUE;
  7902. for(var face=0; face < hullB.faces.length; face++){
  7903. WorldNormal.copy(hullB.faceNormals[face]);
  7904. quatB.vmult(WorldNormal,WorldNormal);
  7905. //posB.vadd(WorldNormal,WorldNormal);
  7906. var d = WorldNormal.dot(separatingNormal);
  7907. if (d > dmax){
  7908. dmax = d;
  7909. closestFaceB = face;
  7910. }
  7911. }
  7912. var worldVertsB1 = [];
  7913. var polyB = hullB.faces[closestFaceB];
  7914. var numVertices = polyB.length;
  7915. for(var e0=0; e0<numVertices; e0++){
  7916. var b = hullB.vertices[polyB[e0]];
  7917. var worldb = new Vec3();
  7918. worldb.copy(b);
  7919. quatB.vmult(worldb,worldb);
  7920. posB.vadd(worldb,worldb);
  7921. worldVertsB1.push(worldb);
  7922. }
  7923. if (closestFaceB>=0){
  7924. this.clipFaceAgainstHull(separatingNormal,
  7925. posA,
  7926. quatA,
  7927. worldVertsB1,
  7928. minDist,
  7929. maxDist,
  7930. result);
  7931. }
  7932. };
  7933. /**
  7934. * Find the separating axis between this hull and another
  7935. * @method findSeparatingAxis
  7936. * @param {ConvexPolyhedron} hullB
  7937. * @param {Vec3} posA
  7938. * @param {Quaternion} quatA
  7939. * @param {Vec3} posB
  7940. * @param {Quaternion} quatB
  7941. * @param {Vec3} target The target vector to save the axis in
  7942. * @return {bool} Returns false if a separation is found, else true
  7943. */
  7944. var fsa_faceANormalWS3 = new Vec3(),
  7945. fsa_Worldnormal1 = new Vec3(),
  7946. fsa_deltaC = new Vec3(),
  7947. fsa_worldEdge0 = new Vec3(),
  7948. fsa_worldEdge1 = new Vec3(),
  7949. fsa_Cross = new Vec3();
  7950. ConvexPolyhedron.prototype.findSeparatingAxis = function(hullB,posA,quatA,posB,quatB,target, faceListA, faceListB){
  7951. var faceANormalWS3 = fsa_faceANormalWS3,
  7952. Worldnormal1 = fsa_Worldnormal1,
  7953. deltaC = fsa_deltaC,
  7954. worldEdge0 = fsa_worldEdge0,
  7955. worldEdge1 = fsa_worldEdge1,
  7956. Cross = fsa_Cross;
  7957. var dmin = Number.MAX_VALUE;
  7958. var hullA = this;
  7959. var curPlaneTests=0;
  7960. if(!hullA.uniqueAxes){
  7961. var numFacesA = faceListA ? faceListA.length : hullA.faces.length;
  7962. // Test face normals from hullA
  7963. for(var i=0; i<numFacesA; i++){
  7964. var fi = faceListA ? faceListA[i] : i;
  7965. // Get world face normal
  7966. faceANormalWS3.copy(hullA.faceNormals[fi]);
  7967. quatA.vmult(faceANormalWS3,faceANormalWS3);
  7968. var d = hullA.testSepAxis(faceANormalWS3, hullB, posA, quatA, posB, quatB);
  7969. if(d===false){
  7970. return false;
  7971. }
  7972. if(d<dmin){
  7973. dmin = d;
  7974. target.copy(faceANormalWS3);
  7975. }
  7976. }
  7977. } else {
  7978. // Test unique axes
  7979. for(var i = 0; i !== hullA.uniqueAxes.length; i++){
  7980. // Get world axis
  7981. quatA.vmult(hullA.uniqueAxes[i],faceANormalWS3);
  7982. var d = hullA.testSepAxis(faceANormalWS3, hullB, posA, quatA, posB, quatB);
  7983. if(d===false){
  7984. return false;
  7985. }
  7986. if(d<dmin){
  7987. dmin = d;
  7988. target.copy(faceANormalWS3);
  7989. }
  7990. }
  7991. }
  7992. if(!hullB.uniqueAxes){
  7993. // Test face normals from hullB
  7994. var numFacesB = faceListB ? faceListB.length : hullB.faces.length;
  7995. for(var i=0;i<numFacesB;i++){
  7996. var fi = faceListB ? faceListB[i] : i;
  7997. Worldnormal1.copy(hullB.faceNormals[fi]);
  7998. quatB.vmult(Worldnormal1,Worldnormal1);
  7999. curPlaneTests++;
  8000. var d = hullA.testSepAxis(Worldnormal1, hullB,posA,quatA,posB,quatB);
  8001. if(d===false){
  8002. return false;
  8003. }
  8004. if(d<dmin){
  8005. dmin = d;
  8006. target.copy(Worldnormal1);
  8007. }
  8008. }
  8009. } else {
  8010. // Test unique axes in B
  8011. for(var i = 0; i !== hullB.uniqueAxes.length; i++){
  8012. quatB.vmult(hullB.uniqueAxes[i],Worldnormal1);
  8013. curPlaneTests++;
  8014. var d = hullA.testSepAxis(Worldnormal1, hullB,posA,quatA,posB,quatB);
  8015. if(d===false){
  8016. return false;
  8017. }
  8018. if(d<dmin){
  8019. dmin = d;
  8020. target.copy(Worldnormal1);
  8021. }
  8022. }
  8023. }
  8024. // Test edges
  8025. for(var e0=0; e0 !== hullA.uniqueEdges.length; e0++){
  8026. // Get world edge
  8027. quatA.vmult(hullA.uniqueEdges[e0],worldEdge0);
  8028. for(var e1=0; e1 !== hullB.uniqueEdges.length; e1++){
  8029. // Get world edge 2
  8030. quatB.vmult(hullB.uniqueEdges[e1], worldEdge1);
  8031. worldEdge0.cross(worldEdge1,Cross);
  8032. if(!Cross.almostZero()){
  8033. Cross.normalize();
  8034. var dist = hullA.testSepAxis(Cross, hullB, posA, quatA, posB, quatB);
  8035. if(dist === false){
  8036. return false;
  8037. }
  8038. if(dist < dmin){
  8039. dmin = dist;
  8040. target.copy(Cross);
  8041. }
  8042. }
  8043. }
  8044. }
  8045. posB.vsub(posA,deltaC);
  8046. if((deltaC.dot(target))>0.0){
  8047. target.negate(target);
  8048. }
  8049. return true;
  8050. };
  8051. var maxminA=[], maxminB=[];
  8052. /**
  8053. * Test separating axis against two hulls. Both hulls are projected onto the axis and the overlap size is returned if there is one.
  8054. * @method testSepAxis
  8055. * @param {Vec3} axis
  8056. * @param {ConvexPolyhedron} hullB
  8057. * @param {Vec3} posA
  8058. * @param {Quaternion} quatA
  8059. * @param {Vec3} posB
  8060. * @param {Quaternion} quatB
  8061. * @return {number} The overlap depth, or FALSE if no penetration.
  8062. */
  8063. ConvexPolyhedron.prototype.testSepAxis = function(axis, hullB, posA, quatA, posB, quatB){
  8064. var hullA=this;
  8065. ConvexPolyhedron.project(hullA, axis, posA, quatA, maxminA);
  8066. ConvexPolyhedron.project(hullB, axis, posB, quatB, maxminB);
  8067. var maxA = maxminA[0];
  8068. var minA = maxminA[1];
  8069. var maxB = maxminB[0];
  8070. var minB = maxminB[1];
  8071. if(maxA<minB || maxB<minA){
  8072. return false; // Separated
  8073. }
  8074. var d0 = maxA - minB;
  8075. var d1 = maxB - minA;
  8076. var depth = d0<d1 ? d0:d1;
  8077. return depth;
  8078. };
  8079. var cli_aabbmin = new Vec3(),
  8080. cli_aabbmax = new Vec3();
  8081. /**
  8082. * @method calculateLocalInertia
  8083. * @param {Number} mass
  8084. * @param {Vec3} target
  8085. */
  8086. ConvexPolyhedron.prototype.calculateLocalInertia = function(mass,target){
  8087. // Approximate with box inertia
  8088. // Exact inertia calculation is overkill, but see http://geometrictools.com/Documentation/PolyhedralMassProperties.pdf for the correct way to do it
  8089. this.computeLocalAABB(cli_aabbmin,cli_aabbmax);
  8090. var x = cli_aabbmax.x - cli_aabbmin.x,
  8091. y = cli_aabbmax.y - cli_aabbmin.y,
  8092. z = cli_aabbmax.z - cli_aabbmin.z;
  8093. target.x = 1.0 / 12.0 * mass * ( 2*y*2*y + 2*z*2*z );
  8094. target.y = 1.0 / 12.0 * mass * ( 2*x*2*x + 2*z*2*z );
  8095. target.z = 1.0 / 12.0 * mass * ( 2*y*2*y + 2*x*2*x );
  8096. };
  8097. /**
  8098. * @method getPlaneConstantOfFace
  8099. * @param {Number} face_i Index of the face
  8100. * @return {Number}
  8101. */
  8102. ConvexPolyhedron.prototype.getPlaneConstantOfFace = function(face_i){
  8103. var f = this.faces[face_i];
  8104. var n = this.faceNormals[face_i];
  8105. var v = this.vertices[f[0]];
  8106. var c = -n.dot(v);
  8107. return c;
  8108. };
  8109. /**
  8110. * Clip a face against a hull.
  8111. * @method clipFaceAgainstHull
  8112. * @param {Vec3} separatingNormal
  8113. * @param {Vec3} posA
  8114. * @param {Quaternion} quatA
  8115. * @param {Array} worldVertsB1 An array of Vec3 with vertices in the world frame.
  8116. * @param {Number} minDist Distance clamping
  8117. * @param {Number} maxDist
  8118. * @param Array result Array to store resulting contact points in. Will be objects with properties: point, depth, normal. These are represented in world coordinates.
  8119. */
  8120. var cfah_faceANormalWS = new Vec3(),
  8121. cfah_edge0 = new Vec3(),
  8122. cfah_WorldEdge0 = new Vec3(),
  8123. cfah_worldPlaneAnormal1 = new Vec3(),
  8124. cfah_planeNormalWS1 = new Vec3(),
  8125. cfah_worldA1 = new Vec3(),
  8126. cfah_localPlaneNormal = new Vec3(),
  8127. cfah_planeNormalWS = new Vec3();
  8128. ConvexPolyhedron.prototype.clipFaceAgainstHull = function(separatingNormal, posA, quatA, worldVertsB1, minDist, maxDist,result){
  8129. var faceANormalWS = cfah_faceANormalWS,
  8130. edge0 = cfah_edge0,
  8131. WorldEdge0 = cfah_WorldEdge0,
  8132. worldPlaneAnormal1 = cfah_worldPlaneAnormal1,
  8133. planeNormalWS1 = cfah_planeNormalWS1,
  8134. worldA1 = cfah_worldA1,
  8135. localPlaneNormal = cfah_localPlaneNormal,
  8136. planeNormalWS = cfah_planeNormalWS;
  8137. var hullA = this;
  8138. var worldVertsB2 = [];
  8139. var pVtxIn = worldVertsB1;
  8140. var pVtxOut = worldVertsB2;
  8141. // Find the face with normal closest to the separating axis
  8142. var closestFaceA = -1;
  8143. var dmin = Number.MAX_VALUE;
  8144. for(var face=0; face<hullA.faces.length; face++){
  8145. faceANormalWS.copy(hullA.faceNormals[face]);
  8146. quatA.vmult(faceANormalWS,faceANormalWS);
  8147. //posA.vadd(faceANormalWS,faceANormalWS);
  8148. var d = faceANormalWS.dot(separatingNormal);
  8149. if (d < dmin){
  8150. dmin = d;
  8151. closestFaceA = face;
  8152. }
  8153. }
  8154. if (closestFaceA < 0){
  8155. // console.log("--- did not find any closest face... ---");
  8156. return;
  8157. }
  8158. //console.log("closest A: ",closestFaceA);
  8159. // Get the face and construct connected faces
  8160. var polyA = hullA.faces[closestFaceA];
  8161. polyA.connectedFaces = [];
  8162. for(var i=0; i<hullA.faces.length; i++){
  8163. for(var j=0; j<hullA.faces[i].length; j++){
  8164. 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 */ ){
  8165. polyA.connectedFaces.push(i);
  8166. }
  8167. }
  8168. }
  8169. // Clip the polygon to the back of the planes of all faces of hull A, that are adjacent to the witness face
  8170. var numContacts = pVtxIn.length;
  8171. var numVerticesA = polyA.length;
  8172. var res = [];
  8173. for(var e0=0; e0<numVerticesA; e0++){
  8174. var a = hullA.vertices[polyA[e0]];
  8175. var b = hullA.vertices[polyA[(e0+1)%numVerticesA]];
  8176. a.vsub(b,edge0);
  8177. WorldEdge0.copy(edge0);
  8178. quatA.vmult(WorldEdge0,WorldEdge0);
  8179. posA.vadd(WorldEdge0,WorldEdge0);
  8180. worldPlaneAnormal1.copy(this.faceNormals[closestFaceA]);//transA.getBasis()* btVector3(polyA.m_plane[0],polyA.m_plane[1],polyA.m_plane[2]);
  8181. quatA.vmult(worldPlaneAnormal1,worldPlaneAnormal1);
  8182. posA.vadd(worldPlaneAnormal1,worldPlaneAnormal1);
  8183. WorldEdge0.cross(worldPlaneAnormal1,planeNormalWS1);
  8184. planeNormalWS1.negate(planeNormalWS1);
  8185. worldA1.copy(a);
  8186. quatA.vmult(worldA1,worldA1);
  8187. posA.vadd(worldA1,worldA1);
  8188. var planeEqWS1 = -worldA1.dot(planeNormalWS1);
  8189. var planeEqWS;
  8190. if(true){
  8191. var otherFace = polyA.connectedFaces[e0];
  8192. localPlaneNormal.copy(this.faceNormals[otherFace]);
  8193. var localPlaneEq = this.getPlaneConstantOfFace(otherFace);
  8194. planeNormalWS.copy(localPlaneNormal);
  8195. quatA.vmult(planeNormalWS,planeNormalWS);
  8196. //posA.vadd(planeNormalWS,planeNormalWS);
  8197. var planeEqWS = localPlaneEq - planeNormalWS.dot(posA);
  8198. } else {
  8199. planeNormalWS.copy(planeNormalWS1);
  8200. planeEqWS = planeEqWS1;
  8201. }
  8202. // Clip face against our constructed plane
  8203. this.clipFaceAgainstPlane(pVtxIn, pVtxOut, planeNormalWS, planeEqWS);
  8204. // Throw away all clipped points, but save the reamining until next clip
  8205. while(pVtxIn.length){
  8206. pVtxIn.shift();
  8207. }
  8208. while(pVtxOut.length){
  8209. pVtxIn.push(pVtxOut.shift());
  8210. }
  8211. }
  8212. //console.log("Resulting points after clip:",pVtxIn);
  8213. // only keep contact points that are behind the witness face
  8214. localPlaneNormal.copy(this.faceNormals[closestFaceA]);
  8215. var localPlaneEq = this.getPlaneConstantOfFace(closestFaceA);
  8216. planeNormalWS.copy(localPlaneNormal);
  8217. quatA.vmult(planeNormalWS,planeNormalWS);
  8218. var planeEqWS = localPlaneEq - planeNormalWS.dot(posA);
  8219. for (var i=0; i<pVtxIn.length; i++){
  8220. var depth = planeNormalWS.dot(pVtxIn[i]) + planeEqWS; //???
  8221. /*console.log("depth calc from normal=",planeNormalWS.toString()," and constant "+planeEqWS+" and vertex ",pVtxIn[i].toString()," gives "+depth);*/
  8222. if (depth <=minDist){
  8223. console.log("clamped: depth="+depth+" to minDist="+(minDist+""));
  8224. depth = minDist;
  8225. }
  8226. if (depth <=maxDist){
  8227. var point = pVtxIn[i];
  8228. if(depth<=0){
  8229. /*console.log("Got contact point ",point.toString(),
  8230. ", depth=",depth,
  8231. "contact normal=",separatingNormal.toString(),
  8232. "plane",planeNormalWS.toString(),
  8233. "planeConstant",planeEqWS);*/
  8234. var p = {
  8235. point:point,
  8236. normal:planeNormalWS,
  8237. depth: depth,
  8238. };
  8239. result.push(p);
  8240. }
  8241. }
  8242. }
  8243. };
  8244. /**
  8245. * Clip a face in a hull against the back of a plane.
  8246. * @method clipFaceAgainstPlane
  8247. * @param {Array} inVertices
  8248. * @param {Array} outVertices
  8249. * @param {Vec3} planeNormal
  8250. * @param {Number} planeConstant The constant in the mathematical plane equation
  8251. */
  8252. ConvexPolyhedron.prototype.clipFaceAgainstPlane = function(inVertices,outVertices, planeNormal, planeConstant){
  8253. var n_dot_first, n_dot_last;
  8254. var numVerts = inVertices.length;
  8255. if(numVerts < 2){
  8256. return outVertices;
  8257. }
  8258. var firstVertex = inVertices[inVertices.length-1],
  8259. lastVertex = inVertices[0];
  8260. n_dot_first = planeNormal.dot(firstVertex) + planeConstant;
  8261. for(var vi = 0; vi < numVerts; vi++){
  8262. lastVertex = inVertices[vi];
  8263. n_dot_last = planeNormal.dot(lastVertex) + planeConstant;
  8264. if(n_dot_first < 0){
  8265. if(n_dot_last < 0){
  8266. // Start < 0, end < 0, so output lastVertex
  8267. var newv = new Vec3();
  8268. newv.copy(lastVertex);
  8269. outVertices.push(newv);
  8270. } else {
  8271. // Start < 0, end >= 0, so output intersection
  8272. var newv = new Vec3();
  8273. firstVertex.lerp(lastVertex,
  8274. n_dot_first / (n_dot_first - n_dot_last),
  8275. newv);
  8276. outVertices.push(newv);
  8277. }
  8278. } else {
  8279. if(n_dot_last<0){
  8280. // Start >= 0, end < 0 so output intersection and end
  8281. var newv = new Vec3();
  8282. firstVertex.lerp(lastVertex,
  8283. n_dot_first / (n_dot_first - n_dot_last),
  8284. newv);
  8285. outVertices.push(newv);
  8286. outVertices.push(lastVertex);
  8287. }
  8288. }
  8289. firstVertex = lastVertex;
  8290. n_dot_first = n_dot_last;
  8291. }
  8292. return outVertices;
  8293. };
  8294. // Updates .worldVertices and sets .worldVerticesNeedsUpdate to false.
  8295. ConvexPolyhedron.prototype.computeWorldVertices = function(position,quat){
  8296. var N = this.vertices.length;
  8297. while(this.worldVertices.length < N){
  8298. this.worldVertices.push( new Vec3() );
  8299. }
  8300. var verts = this.vertices,
  8301. worldVerts = this.worldVertices;
  8302. for(var i=0; i!==N; i++){
  8303. quat.vmult( verts[i] , worldVerts[i] );
  8304. position.vadd( worldVerts[i] , worldVerts[i] );
  8305. }
  8306. this.worldVerticesNeedsUpdate = false;
  8307. };
  8308. var computeLocalAABB_worldVert = new Vec3();
  8309. ConvexPolyhedron.prototype.computeLocalAABB = function(aabbmin,aabbmax){
  8310. var n = this.vertices.length,
  8311. vertices = this.vertices,
  8312. worldVert = computeLocalAABB_worldVert;
  8313. aabbmin.set(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  8314. aabbmax.set(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
  8315. for(var i=0; i<n; i++){
  8316. var v = vertices[i];
  8317. if (v.x < aabbmin.x){
  8318. aabbmin.x = v.x;
  8319. } else if(v.x > aabbmax.x){
  8320. aabbmax.x = v.x;
  8321. }
  8322. if (v.y < aabbmin.y){
  8323. aabbmin.y = v.y;
  8324. } else if(v.y > aabbmax.y){
  8325. aabbmax.y = v.y;
  8326. }
  8327. if (v.z < aabbmin.z){
  8328. aabbmin.z = v.z;
  8329. } else if(v.z > aabbmax.z){
  8330. aabbmax.z = v.z;
  8331. }
  8332. }
  8333. };
  8334. /**
  8335. * Updates .worldVertices and sets .worldVerticesNeedsUpdate to false.
  8336. * @method computeWorldFaceNormals
  8337. * @param {Quaternion} quat
  8338. */
  8339. ConvexPolyhedron.prototype.computeWorldFaceNormals = function(quat){
  8340. var N = this.faceNormals.length;
  8341. while(this.worldFaceNormals.length < N){
  8342. this.worldFaceNormals.push( new Vec3() );
  8343. }
  8344. var normals = this.faceNormals,
  8345. worldNormals = this.worldFaceNormals;
  8346. for(var i=0; i!==N; i++){
  8347. quat.vmult( normals[i] , worldNormals[i] );
  8348. }
  8349. this.worldFaceNormalsNeedsUpdate = false;
  8350. };
  8351. /**
  8352. * @method updateBoundingSphereRadius
  8353. */
  8354. ConvexPolyhedron.prototype.updateBoundingSphereRadius = function(){
  8355. // Assume points are distributed with local (0,0,0) as center
  8356. var max2 = 0;
  8357. var verts = this.vertices;
  8358. for(var i=0, N=verts.length; i!==N; i++) {
  8359. var norm2 = verts[i].norm2();
  8360. if(norm2 > max2){
  8361. max2 = norm2;
  8362. }
  8363. }
  8364. this.boundingSphereRadius = Math.sqrt(max2);
  8365. };
  8366. var tempWorldVertex = new Vec3();
  8367. /**
  8368. * @method calculateWorldAABB
  8369. * @param {Vec3} pos
  8370. * @param {Quaternion} quat
  8371. * @param {Vec3} min
  8372. * @param {Vec3} max
  8373. */
  8374. ConvexPolyhedron.prototype.calculateWorldAABB = function(pos,quat,min,max){
  8375. var n = this.vertices.length, verts = this.vertices;
  8376. var minx,miny,minz,maxx,maxy,maxz;
  8377. for(var i=0; i<n; i++){
  8378. tempWorldVertex.copy(verts[i]);
  8379. quat.vmult(tempWorldVertex,tempWorldVertex);
  8380. pos.vadd(tempWorldVertex,tempWorldVertex);
  8381. var v = tempWorldVertex;
  8382. if (v.x < minx || minx===undefined){
  8383. minx = v.x;
  8384. } else if(v.x > maxx || maxx===undefined){
  8385. maxx = v.x;
  8386. }
  8387. if (v.y < miny || miny===undefined){
  8388. miny = v.y;
  8389. } else if(v.y > maxy || maxy===undefined){
  8390. maxy = v.y;
  8391. }
  8392. if (v.z < minz || minz===undefined){
  8393. minz = v.z;
  8394. } else if(v.z > maxz || maxz===undefined){
  8395. maxz = v.z;
  8396. }
  8397. }
  8398. min.set(minx,miny,minz);
  8399. max.set(maxx,maxy,maxz);
  8400. };
  8401. /**
  8402. * Get approximate convex volume
  8403. * @method volume
  8404. * @return {Number}
  8405. */
  8406. ConvexPolyhedron.prototype.volume = function(){
  8407. return 4.0 * Math.PI * this.boundingSphereRadius / 3.0;
  8408. };
  8409. /**
  8410. * Get an average of all the vertices positions
  8411. * @method getAveragePointLocal
  8412. * @param {Vec3} target
  8413. * @return {Vec3}
  8414. */
  8415. ConvexPolyhedron.prototype.getAveragePointLocal = function(target){
  8416. target = target || new Vec3();
  8417. var n = this.vertices.length,
  8418. verts = this.vertices;
  8419. for(var i=0; i<n; i++){
  8420. target.vadd(verts[i],target);
  8421. }
  8422. target.mult(1/n,target);
  8423. return target;
  8424. };
  8425. /**
  8426. * Transform all local points. Will change the .vertices
  8427. * @method transformAllPoints
  8428. * @param {Vec3} offset
  8429. * @param {Quaternion} quat
  8430. */
  8431. ConvexPolyhedron.prototype.transformAllPoints = function(offset,quat){
  8432. var n = this.vertices.length,
  8433. verts = this.vertices;
  8434. // Apply rotation
  8435. if(quat){
  8436. // Rotate vertices
  8437. for(var i=0; i<n; i++){
  8438. var v = verts[i];
  8439. quat.vmult(v,v);
  8440. }
  8441. // Rotate face normals
  8442. for(var i=0; i<this.faceNormals.length; i++){
  8443. var v = this.faceNormals[i];
  8444. quat.vmult(v,v);
  8445. }
  8446. /*
  8447. // Rotate edges
  8448. for(var i=0; i<this.uniqueEdges.length; i++){
  8449. var v = this.uniqueEdges[i];
  8450. quat.vmult(v,v);
  8451. }*/
  8452. }
  8453. // Apply offset
  8454. if(offset){
  8455. for(var i=0; i<n; i++){
  8456. var v = verts[i];
  8457. v.vadd(offset,v);
  8458. }
  8459. }
  8460. };
  8461. /**
  8462. * 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.
  8463. * @method pointIsInside
  8464. * @param {Vec3} p A point given in local coordinates
  8465. * @return {Boolean}
  8466. */
  8467. var ConvexPolyhedron_pointIsInside = new Vec3();
  8468. var ConvexPolyhedron_vToP = new Vec3();
  8469. var ConvexPolyhedron_vToPointInside = new Vec3();
  8470. ConvexPolyhedron.prototype.pointIsInside = function(p){
  8471. var n = this.vertices.length,
  8472. verts = this.vertices,
  8473. faces = this.faces,
  8474. normals = this.faceNormals;
  8475. var positiveResult = null;
  8476. var N = this.faces.length;
  8477. var pointInside = ConvexPolyhedron_pointIsInside;
  8478. this.getAveragePointLocal(pointInside);
  8479. for(var i=0; i<N; i++){
  8480. var numVertices = this.faces[i].length;
  8481. var n = normals[i];
  8482. var v = verts[faces[i][0]]; // We only need one point in the face
  8483. // This dot product determines which side of the edge the point is
  8484. var vToP = ConvexPolyhedron_vToP;
  8485. p.vsub(v,vToP);
  8486. var r1 = n.dot(vToP);
  8487. var vToPointInside = ConvexPolyhedron_vToPointInside;
  8488. pointInside.vsub(v,vToPointInside);
  8489. var r2 = n.dot(vToPointInside);
  8490. if((r1<0 && r2>0) || (r1>0 && r2<0)){
  8491. return false; // Encountered some other sign. Exit.
  8492. } else {
  8493. }
  8494. }
  8495. // If we got here, all dot products were of the same sign.
  8496. return positiveResult ? 1 : -1;
  8497. };
  8498. /**
  8499. * 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.
  8500. * @static
  8501. * @method project
  8502. * @param {ConvexPolyhedron} hull
  8503. * @param {Vec3} axis
  8504. * @param {Vec3} pos
  8505. * @param {Quaternion} quat
  8506. * @param {array} result result[0] and result[1] will be set to maximum and minimum, respectively.
  8507. */
  8508. var project_worldVertex = new Vec3();
  8509. var project_localAxis = new Vec3();
  8510. var project_localOrigin = new Vec3();
  8511. ConvexPolyhedron.project = function(hull, axis, pos, quat, result){
  8512. var n = hull.vertices.length,
  8513. worldVertex = project_worldVertex,
  8514. localAxis = project_localAxis,
  8515. max = 0,
  8516. min = 0,
  8517. localOrigin = project_localOrigin,
  8518. vs = hull.vertices;
  8519. localOrigin.setZero();
  8520. // Transform the axis to local
  8521. Transform.vectorToLocalFrame(pos, quat, axis, localAxis);
  8522. Transform.pointToLocalFrame(pos, quat, localOrigin, localOrigin);
  8523. var add = localOrigin.dot(localAxis);
  8524. min = max = vs[0].dot(localAxis);
  8525. for(var i = 1; i < n; i++){
  8526. var val = vs[i].dot(localAxis);
  8527. if(val > max){
  8528. max = val;
  8529. }
  8530. if(val < min){
  8531. min = val;
  8532. }
  8533. }
  8534. min -= add;
  8535. max -= add;
  8536. if(min > max){
  8537. // Inconsistent - swap
  8538. var temp = min;
  8539. min = max;
  8540. max = temp;
  8541. }
  8542. // Output
  8543. result[0] = max;
  8544. result[1] = min;
  8545. };
  8546. },{"../math/Quaternion":41,"../math/Transform":42,"../math/Vec3":43,"./Shape":56}],52:[function(require,module,exports){
  8547. module.exports = Cylinder;
  8548. var Shape = require('./Shape');
  8549. var Vec3 = require('../math/Vec3');
  8550. var Quaternion = require('../math/Quaternion');
  8551. var ConvexPolyhedron = require('./ConvexPolyhedron');
  8552. /**
  8553. * @class Cylinder
  8554. * @constructor
  8555. * @extends ConvexPolyhedron
  8556. * @author schteppe / https://github.com/schteppe
  8557. * @param {Number} radiusTop
  8558. * @param {Number} radiusBottom
  8559. * @param {Number} height
  8560. * @param {Number} numSegments The number of segments to build the cylinder out of
  8561. */
  8562. function Cylinder( radiusTop, radiusBottom, height , numSegments ) {
  8563. var N = numSegments,
  8564. verts = [],
  8565. axes = [],
  8566. faces = [],
  8567. bottomface = [],
  8568. topface = [],
  8569. cos = Math.cos,
  8570. sin = Math.sin;
  8571. // First bottom point
  8572. verts.push(new Vec3(radiusBottom*cos(0),
  8573. radiusBottom*sin(0),
  8574. -height*0.5));
  8575. bottomface.push(0);
  8576. // First top point
  8577. verts.push(new Vec3(radiusTop*cos(0),
  8578. radiusTop*sin(0),
  8579. height*0.5));
  8580. topface.push(1);
  8581. for(var i=0; i<N; i++){
  8582. var theta = 2*Math.PI/N * (i+1);
  8583. var thetaN = 2*Math.PI/N * (i+0.5);
  8584. if(i<N-1){
  8585. // Bottom
  8586. verts.push(new Vec3(radiusBottom*cos(theta),
  8587. radiusBottom*sin(theta),
  8588. -height*0.5));
  8589. bottomface.push(2*i+2);
  8590. // Top
  8591. verts.push(new Vec3(radiusTop*cos(theta),
  8592. radiusTop*sin(theta),
  8593. height*0.5));
  8594. topface.push(2*i+3);
  8595. // Face
  8596. faces.push([2*i+2, 2*i+3, 2*i+1,2*i]);
  8597. } else {
  8598. faces.push([0,1, 2*i+1, 2*i]); // Connect
  8599. }
  8600. // Axis: we can cut off half of them if we have even number of segments
  8601. if(N % 2 === 1 || i < N / 2){
  8602. axes.push(new Vec3(cos(thetaN), sin(thetaN), 0));
  8603. }
  8604. }
  8605. faces.push(topface);
  8606. axes.push(new Vec3(0,0,1));
  8607. // Reorder bottom face
  8608. var temp = [];
  8609. for(var i=0; i<bottomface.length; i++){
  8610. temp.push(bottomface[bottomface.length - i - 1]);
  8611. }
  8612. faces.push(temp);
  8613. this.type = Shape.types.CONVEXPOLYHEDRON;
  8614. ConvexPolyhedron.call( this, verts, faces, axes );
  8615. }
  8616. Cylinder.prototype = new ConvexPolyhedron();
  8617. },{"../math/Quaternion":41,"../math/Vec3":43,"./ConvexPolyhedron":51,"./Shape":56}],53:[function(require,module,exports){
  8618. var Shape = require('./Shape');
  8619. var ConvexPolyhedron = require('./ConvexPolyhedron');
  8620. var Vec3 = require('../math/Vec3');
  8621. var Utils = require('../utils/Utils');
  8622. module.exports = Heightfield;
  8623. /**
  8624. * Heightfield shape class. Height data is given as an array. These data points are spread out evenly with a given distance.
  8625. * @class Heightfield
  8626. * @extends Shape
  8627. * @constructor
  8628. * @param {Array} data An array of Y values that will be used to construct the terrain.
  8629. * @param {object} options
  8630. * @param {Number} [options.minValue] Minimum value of the data points in the data array. Will be computed automatically if not given.
  8631. * @param {Number} [options.maxValue] Maximum value.
  8632. * @param {Number} [options.elementSize=0.1] World spacing between the data points in X direction.
  8633. * @todo Should be possible to use along all axes, not just y
  8634. * @todo should be possible to scale along all axes
  8635. *
  8636. * @example
  8637. * // Generate some height data (y-values).
  8638. * var data = [];
  8639. * for(var i = 0; i < 1000; i++){
  8640. * var y = 0.5 * Math.cos(0.2 * i);
  8641. * data.push(y);
  8642. * }
  8643. *
  8644. * // Create the heightfield shape
  8645. * var heightfieldShape = new Heightfield(data, {
  8646. * elementSize: 1 // Distance between the data points in X and Y directions
  8647. * });
  8648. * var heightfieldBody = new Body();
  8649. * heightfieldBody.addShape(heightfieldShape);
  8650. * world.addBody(heightfieldBody);
  8651. */
  8652. function Heightfield(data, options){
  8653. options = Utils.defaults(options, {
  8654. maxValue : null,
  8655. minValue : null,
  8656. elementSize : 1
  8657. });
  8658. /**
  8659. * An array of numbers, or height values, that are spread out along the x axis.
  8660. * @property {array} data
  8661. */
  8662. this.data = data;
  8663. /**
  8664. * Max value of the data
  8665. * @property {number} maxValue
  8666. */
  8667. this.maxValue = options.maxValue;
  8668. /**
  8669. * Max value of the data
  8670. * @property {number} minValue
  8671. */
  8672. this.minValue = options.minValue;
  8673. /**
  8674. * The width of each element
  8675. * @property {number} elementSize
  8676. * @todo elementSizeX and Y
  8677. */
  8678. this.elementSize = options.elementSize;
  8679. if(options.minValue === null){
  8680. this.updateMinValue();
  8681. }
  8682. if(options.maxValue === null){
  8683. this.updateMaxValue();
  8684. }
  8685. this.cacheEnabled = true;
  8686. Shape.call(this);
  8687. this.pillarConvex = new ConvexPolyhedron();
  8688. this.pillarOffset = new Vec3();
  8689. this.type = Shape.types.HEIGHTFIELD;
  8690. this.updateBoundingSphereRadius();
  8691. // "i_j_isUpper" => { convex: ..., offset: ... }
  8692. // for example:
  8693. // _cachedPillars["0_2_1"]
  8694. this._cachedPillars = {};
  8695. }
  8696. Heightfield.prototype = new Shape();
  8697. /**
  8698. * Call whenever you change the data array.
  8699. * @method update
  8700. */
  8701. Heightfield.prototype.update = function(){
  8702. this._cachedPillars = {};
  8703. };
  8704. /**
  8705. * Update the .minValue property
  8706. * @method updateMinValue
  8707. */
  8708. Heightfield.prototype.updateMinValue = function(){
  8709. var data = this.data;
  8710. var minValue = data[0][0];
  8711. for(var i=0; i !== data.length; i++){
  8712. for(var j=0; j !== data[i].length; j++){
  8713. var v = data[i][j];
  8714. if(v < minValue){
  8715. minValue = v;
  8716. }
  8717. }
  8718. }
  8719. this.minValue = minValue;
  8720. };
  8721. /**
  8722. * Update the .maxValue property
  8723. * @method updateMaxValue
  8724. */
  8725. Heightfield.prototype.updateMaxValue = function(){
  8726. var data = this.data;
  8727. var maxValue = data[0][0];
  8728. for(var i=0; i !== data.length; i++){
  8729. for(var j=0; j !== data[i].length; j++){
  8730. var v = data[i][j];
  8731. if(v > maxValue){
  8732. maxValue = v;
  8733. }
  8734. }
  8735. }
  8736. this.maxValue = maxValue;
  8737. };
  8738. /**
  8739. * Set the height value at an index. Don't forget to update maxValue and minValue after you're done.
  8740. * @method setHeightValueAtIndex
  8741. * @param {integer} xi
  8742. * @param {integer} yi
  8743. * @param {number} value
  8744. */
  8745. Heightfield.prototype.setHeightValueAtIndex = function(xi, yi, value){
  8746. var data = this.data;
  8747. data[xi][yi] = value;
  8748. // Invalidate cache
  8749. this.clearCachedConvexTrianglePillar(xi, yi, false);
  8750. if(xi > 0){
  8751. this.clearCachedConvexTrianglePillar(xi - 1, yi, true);
  8752. this.clearCachedConvexTrianglePillar(xi - 1, yi, false);
  8753. }
  8754. if(yi > 0){
  8755. this.clearCachedConvexTrianglePillar(xi, yi - 1, true);
  8756. this.clearCachedConvexTrianglePillar(xi, yi - 1, false);
  8757. }
  8758. if(yi > 0 && xi > 0){
  8759. this.clearCachedConvexTrianglePillar(xi - 1, yi - 1, true);
  8760. }
  8761. };
  8762. /**
  8763. * Get max/min in a rectangle in the matrix data
  8764. * @method getRectMinMax
  8765. * @param {integer} iMinX
  8766. * @param {integer} iMinY
  8767. * @param {integer} iMaxX
  8768. * @param {integer} iMaxY
  8769. * @param {array} [result] An array to store the results in.
  8770. * @return {array} The result array, if it was passed in. Minimum will be at position 0 and max at 1.
  8771. */
  8772. Heightfield.prototype.getRectMinMax = function (iMinX, iMinY, iMaxX, iMaxY, result) {
  8773. result = result || [];
  8774. // Get max and min of the data
  8775. var data = this.data,
  8776. max = this.minValue; // Set first value
  8777. for(var i = iMinX; i <= iMaxX; i++){
  8778. for(var j = iMinY; j <= iMaxY; j++){
  8779. var height = data[i][j];
  8780. if(height > max){
  8781. max = height;
  8782. }
  8783. }
  8784. }
  8785. result[0] = this.minValue;
  8786. result[1] = max;
  8787. };
  8788. /**
  8789. * 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.
  8790. * @method getIndexOfPosition
  8791. * @param {number} x
  8792. * @param {number} y
  8793. * @param {array} result Two-element array
  8794. * @param {boolean} clamp If the position should be clamped to the heightfield edge.
  8795. * @return {boolean}
  8796. */
  8797. Heightfield.prototype.getIndexOfPosition = function (x, y, result, clamp) {
  8798. // Get the index of the data points to test against
  8799. var w = this.elementSize;
  8800. var data = this.data;
  8801. var xi = Math.floor(x / w);
  8802. var yi = Math.floor(y / w);
  8803. result[0] = xi;
  8804. result[1] = yi;
  8805. if(clamp){
  8806. // Clamp index to edges
  8807. if(xi < 0){ xi = 0; }
  8808. if(yi < 0){ yi = 0; }
  8809. if(xi >= data.length - 1){ xi = data.length - 1; }
  8810. if(yi >= data[0].length - 1){ yi = data[0].length - 1; }
  8811. }
  8812. // Bail out if we are out of the terrain
  8813. if(xi < 0 || yi < 0 || xi >= data.length-1 || yi >= data[0].length-1){
  8814. return false;
  8815. }
  8816. return true;
  8817. };
  8818. var getHeightAt_idx = [];
  8819. var getHeightAt_weights = new Vec3();
  8820. var getHeightAt_a = new Vec3();
  8821. var getHeightAt_b = new Vec3();
  8822. var getHeightAt_c = new Vec3();
  8823. Heightfield.prototype.getTriangleAt = function(x, y, edgeClamp, a, b, c){
  8824. var idx = getHeightAt_idx;
  8825. this.getIndexOfPosition(x, y, idx, edgeClamp);
  8826. var xi = idx[0];
  8827. var yi = idx[1];
  8828. var data = this.data;
  8829. if(edgeClamp){
  8830. xi = Math.min(data.length - 2, Math.max(0, xi));
  8831. yi = Math.min(data[0].length - 2, Math.max(0, yi));
  8832. }
  8833. var elementSize = this.elementSize;
  8834. var lowerDist2 = Math.pow(x / elementSize - xi, 2) + Math.pow(y / elementSize - yi, 2);
  8835. var upperDist2 = Math.pow(x / elementSize - (xi + 1), 2) + Math.pow(y / elementSize - (yi + 1), 2);
  8836. var upper = lowerDist2 > upperDist2;
  8837. this.getTriangle(xi, yi, upper, a, b, c);
  8838. return upper;
  8839. };
  8840. var getNormalAt_a = new Vec3();
  8841. var getNormalAt_b = new Vec3();
  8842. var getNormalAt_c = new Vec3();
  8843. var getNormalAt_e0 = new Vec3();
  8844. var getNormalAt_e1 = new Vec3();
  8845. Heightfield.prototype.getNormalAt = function(x, y, edgeClamp, result){
  8846. var a = getNormalAt_a;
  8847. var b = getNormalAt_b;
  8848. var c = getNormalAt_c;
  8849. var e0 = getNormalAt_e0;
  8850. var e1 = getNormalAt_e1;
  8851. this.getTriangleAt(x, y, edgeClamp, a, b, c);
  8852. b.vsub(a, e0);
  8853. c.vsub(a, e1);
  8854. e0.cross(e1, result);
  8855. result.normalize();
  8856. };
  8857. /**
  8858. * Get an AABB of a square in the heightfield
  8859. * @param {number} xi
  8860. * @param {number} yi
  8861. * @param {AABB} result
  8862. */
  8863. Heightfield.prototype.getAabbAtIndex = function(xi, yi, result){
  8864. var data = this.data;
  8865. var elementSize = this.elementSize;
  8866. result.lowerBound.set(
  8867. xi * elementSize,
  8868. yi * elementSize,
  8869. data[xi][yi]
  8870. );
  8871. result.upperBound.set(
  8872. (xi + 1) * elementSize,
  8873. (yi + 1) * elementSize,
  8874. data[xi + 1][yi + 1]
  8875. );
  8876. };
  8877. /**
  8878. * Get the height in the heightfield at a given position
  8879. * @param {number} x
  8880. * @param {number} y
  8881. * @param {boolean} edgeClamp
  8882. * @return {number}
  8883. */
  8884. Heightfield.prototype.getHeightAt = function(x, y, edgeClamp){
  8885. var data = this.data;
  8886. var a = getHeightAt_a;
  8887. var b = getHeightAt_b;
  8888. var c = getHeightAt_c;
  8889. var idx = getHeightAt_idx;
  8890. this.getIndexOfPosition(x, y, idx, edgeClamp);
  8891. var xi = idx[0];
  8892. var yi = idx[1];
  8893. if(edgeClamp){
  8894. xi = Math.min(data.length - 2, Math.max(0, xi));
  8895. yi = Math.min(data[0].length - 2, Math.max(0, yi));
  8896. }
  8897. var upper = this.getTriangleAt(x, y, edgeClamp, a, b, c);
  8898. barycentricWeights(x, y, a.x, a.y, b.x, b.y, c.x, c.y, getHeightAt_weights);
  8899. var w = getHeightAt_weights;
  8900. if(upper){
  8901. // Top triangle verts
  8902. return data[xi + 1][yi + 1] * w.x + data[xi][yi + 1] * w.y + data[xi + 1][yi] * w.z;
  8903. } else {
  8904. // Top triangle verts
  8905. return data[xi][yi] * w.x + data[xi + 1][yi] * w.y + data[xi][yi + 1] * w.z;
  8906. }
  8907. };
  8908. // from https://en.wikipedia.org/wiki/Barycentric_coordinate_system
  8909. function barycentricWeights(x, y, ax, ay, bx, by, cx, cy, result){
  8910. result.x = ((by - cy) * (x - cx) + (cx - bx) * (y - cy)) / ((by - cy) * (ax - cx) + (cx - bx) * (ay - cy));
  8911. result.y = ((cy - ay) * (x - cx) + (ax - cx) * (y - cy)) / ((by - cy) * (ax - cx) + (cx - bx) * (ay - cy));
  8912. result.z = 1 - result.x - result.y;
  8913. }
  8914. Heightfield.prototype.getCacheConvexTrianglePillarKey = function(xi, yi, getUpperTriangle){
  8915. return xi + '_' + yi + '_' + (getUpperTriangle ? 1 : 0);
  8916. };
  8917. Heightfield.prototype.getCachedConvexTrianglePillar = function(xi, yi, getUpperTriangle){
  8918. return this._cachedPillars[this.getCacheConvexTrianglePillarKey(xi, yi, getUpperTriangle)];
  8919. };
  8920. Heightfield.prototype.setCachedConvexTrianglePillar = function(xi, yi, getUpperTriangle, convex, offset){
  8921. this._cachedPillars[this.getCacheConvexTrianglePillarKey(xi, yi, getUpperTriangle)] = {
  8922. convex: convex,
  8923. offset: offset
  8924. };
  8925. };
  8926. Heightfield.prototype.clearCachedConvexTrianglePillar = function(xi, yi, getUpperTriangle){
  8927. delete this._cachedPillars[this.getCacheConvexTrianglePillarKey(xi, yi, getUpperTriangle)];
  8928. };
  8929. /**
  8930. * Get a triangle from the heightfield
  8931. * @param {number} xi
  8932. * @param {number} yi
  8933. * @param {boolean} upper
  8934. * @param {Vec3} a
  8935. * @param {Vec3} b
  8936. * @param {Vec3} c
  8937. */
  8938. Heightfield.prototype.getTriangle = function(xi, yi, upper, a, b, c){
  8939. var data = this.data;
  8940. var elementSize = this.elementSize;
  8941. if(upper){
  8942. // Top triangle verts
  8943. a.set(
  8944. (xi + 1) * elementSize,
  8945. (yi + 1) * elementSize,
  8946. data[xi + 1][yi + 1]
  8947. );
  8948. b.set(
  8949. xi * elementSize,
  8950. (yi + 1) * elementSize,
  8951. data[xi][yi + 1]
  8952. );
  8953. c.set(
  8954. (xi + 1) * elementSize,
  8955. yi * elementSize,
  8956. data[xi + 1][yi]
  8957. );
  8958. } else {
  8959. // Top triangle verts
  8960. a.set(
  8961. xi * elementSize,
  8962. yi * elementSize,
  8963. data[xi][yi]
  8964. );
  8965. b.set(
  8966. (xi + 1) * elementSize,
  8967. yi * elementSize,
  8968. data[xi + 1][yi]
  8969. );
  8970. c.set(
  8971. xi * elementSize,
  8972. (yi + 1) * elementSize,
  8973. data[xi][yi + 1]
  8974. );
  8975. }
  8976. };
  8977. /**
  8978. * Get a triangle in the terrain in the form of a triangular convex shape.
  8979. * @method getConvexTrianglePillar
  8980. * @param {integer} i
  8981. * @param {integer} j
  8982. * @param {boolean} getUpperTriangle
  8983. */
  8984. Heightfield.prototype.getConvexTrianglePillar = function(xi, yi, getUpperTriangle){
  8985. var result = this.pillarConvex;
  8986. var offsetResult = this.pillarOffset;
  8987. if(this.cacheEnabled){
  8988. var data = this.getCachedConvexTrianglePillar(xi, yi, getUpperTriangle);
  8989. if(data){
  8990. this.pillarConvex = data.convex;
  8991. this.pillarOffset = data.offset;
  8992. return;
  8993. }
  8994. result = new ConvexPolyhedron();
  8995. offsetResult = new Vec3();
  8996. this.pillarConvex = result;
  8997. this.pillarOffset = offsetResult;
  8998. }
  8999. var data = this.data;
  9000. var elementSize = this.elementSize;
  9001. var faces = result.faces;
  9002. // Reuse verts if possible
  9003. result.vertices.length = 6;
  9004. for (var i = 0; i < 6; i++) {
  9005. if(!result.vertices[i]){
  9006. result.vertices[i] = new Vec3();
  9007. }
  9008. }
  9009. // Reuse faces if possible
  9010. faces.length = 5;
  9011. for (var i = 0; i < 5; i++) {
  9012. if(!faces[i]){
  9013. faces[i] = [];
  9014. }
  9015. }
  9016. var verts = result.vertices;
  9017. var h = (Math.min(
  9018. data[xi][yi],
  9019. data[xi+1][yi],
  9020. data[xi][yi+1],
  9021. data[xi+1][yi+1]
  9022. ) - this.minValue ) / 2 + this.minValue;
  9023. if (!getUpperTriangle) {
  9024. // Center of the triangle pillar - all polygons are given relative to this one
  9025. offsetResult.set(
  9026. (xi + 0.25) * elementSize, // sort of center of a triangle
  9027. (yi + 0.25) * elementSize,
  9028. h // vertical center
  9029. );
  9030. // Top triangle verts
  9031. verts[0].set(
  9032. -0.25 * elementSize,
  9033. -0.25 * elementSize,
  9034. data[xi][yi] - h
  9035. );
  9036. verts[1].set(
  9037. 0.75 * elementSize,
  9038. -0.25 * elementSize,
  9039. data[xi + 1][yi] - h
  9040. );
  9041. verts[2].set(
  9042. -0.25 * elementSize,
  9043. 0.75 * elementSize,
  9044. data[xi][yi + 1] - h
  9045. );
  9046. // bottom triangle verts
  9047. verts[3].set(
  9048. -0.25 * elementSize,
  9049. -0.25 * elementSize,
  9050. -h-1
  9051. );
  9052. verts[4].set(
  9053. 0.75 * elementSize,
  9054. -0.25 * elementSize,
  9055. -h-1
  9056. );
  9057. verts[5].set(
  9058. -0.25 * elementSize,
  9059. 0.75 * elementSize,
  9060. -h-1
  9061. );
  9062. // top triangle
  9063. faces[0][0] = 0;
  9064. faces[0][1] = 1;
  9065. faces[0][2] = 2;
  9066. // bottom triangle
  9067. faces[1][0] = 5;
  9068. faces[1][1] = 4;
  9069. faces[1][2] = 3;
  9070. // -x facing quad
  9071. faces[2][0] = 0;
  9072. faces[2][1] = 2;
  9073. faces[2][2] = 5;
  9074. faces[2][3] = 3;
  9075. // -y facing quad
  9076. faces[3][0] = 1;
  9077. faces[3][1] = 0;
  9078. faces[3][2] = 3;
  9079. faces[3][3] = 4;
  9080. // +xy facing quad
  9081. faces[4][0] = 4;
  9082. faces[4][1] = 5;
  9083. faces[4][2] = 2;
  9084. faces[4][3] = 1;
  9085. } else {
  9086. // Center of the triangle pillar - all polygons are given relative to this one
  9087. offsetResult.set(
  9088. (xi + 0.75) * elementSize, // sort of center of a triangle
  9089. (yi + 0.75) * elementSize,
  9090. h // vertical center
  9091. );
  9092. // Top triangle verts
  9093. verts[0].set(
  9094. 0.25 * elementSize,
  9095. 0.25 * elementSize,
  9096. data[xi + 1][yi + 1] - h
  9097. );
  9098. verts[1].set(
  9099. -0.75 * elementSize,
  9100. 0.25 * elementSize,
  9101. data[xi][yi + 1] - h
  9102. );
  9103. verts[2].set(
  9104. 0.25 * elementSize,
  9105. -0.75 * elementSize,
  9106. data[xi + 1][yi] - h
  9107. );
  9108. // bottom triangle verts
  9109. verts[3].set(
  9110. 0.25 * elementSize,
  9111. 0.25 * elementSize,
  9112. - h-1
  9113. );
  9114. verts[4].set(
  9115. -0.75 * elementSize,
  9116. 0.25 * elementSize,
  9117. - h-1
  9118. );
  9119. verts[5].set(
  9120. 0.25 * elementSize,
  9121. -0.75 * elementSize,
  9122. - h-1
  9123. );
  9124. // Top triangle
  9125. faces[0][0] = 0;
  9126. faces[0][1] = 1;
  9127. faces[0][2] = 2;
  9128. // bottom triangle
  9129. faces[1][0] = 5;
  9130. faces[1][1] = 4;
  9131. faces[1][2] = 3;
  9132. // +x facing quad
  9133. faces[2][0] = 2;
  9134. faces[2][1] = 5;
  9135. faces[2][2] = 3;
  9136. faces[2][3] = 0;
  9137. // +y facing quad
  9138. faces[3][0] = 3;
  9139. faces[3][1] = 4;
  9140. faces[3][2] = 1;
  9141. faces[3][3] = 0;
  9142. // -xy facing quad
  9143. faces[4][0] = 1;
  9144. faces[4][1] = 4;
  9145. faces[4][2] = 5;
  9146. faces[4][3] = 2;
  9147. }
  9148. result.computeNormals();
  9149. result.computeEdges();
  9150. result.updateBoundingSphereRadius();
  9151. this.setCachedConvexTrianglePillar(xi, yi, getUpperTriangle, result, offsetResult);
  9152. };
  9153. Heightfield.prototype.calculateLocalInertia = function(mass, target){
  9154. target = target || new Vec3();
  9155. target.set(0, 0, 0);
  9156. return target;
  9157. };
  9158. Heightfield.prototype.volume = function(){
  9159. return Number.MAX_VALUE; // The terrain is infinite
  9160. };
  9161. Heightfield.prototype.calculateWorldAABB = function(pos, quat, min, max){
  9162. // TODO: do it properly
  9163. min.set(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
  9164. max.set(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  9165. };
  9166. Heightfield.prototype.updateBoundingSphereRadius = function(){
  9167. // Use the bounding box of the min/max values
  9168. var data = this.data,
  9169. s = this.elementSize;
  9170. this.boundingSphereRadius = new Vec3(data.length * s, data[0].length * s, Math.max(Math.abs(this.maxValue), Math.abs(this.minValue))).norm();
  9171. };
  9172. /**
  9173. * Sets the height values from an image. Currently only supported in browser.
  9174. * @method setHeightsFromImage
  9175. * @param {Image} image
  9176. * @param {Vec3} scale
  9177. */
  9178. Heightfield.prototype.setHeightsFromImage = function(image, scale){
  9179. var canvas = document.createElement('canvas');
  9180. canvas.width = image.width;
  9181. canvas.height = image.height;
  9182. var context = canvas.getContext('2d');
  9183. context.drawImage(image, 0, 0);
  9184. var imageData = context.getImageData(0, 0, image.width, image.height);
  9185. var matrix = this.data;
  9186. matrix.length = 0;
  9187. this.elementSize = Math.abs(scale.x) / imageData.width;
  9188. for(var i=0; i<imageData.height; i++){
  9189. var row = [];
  9190. for(var j=0; j<imageData.width; j++){
  9191. var a = imageData.data[(i*imageData.height + j) * 4];
  9192. var b = imageData.data[(i*imageData.height + j) * 4 + 1];
  9193. var c = imageData.data[(i*imageData.height + j) * 4 + 2];
  9194. var height = (a + b + c) / 4 / 255 * scale.z;
  9195. if(scale.x < 0){
  9196. row.push(height);
  9197. } else {
  9198. row.unshift(height);
  9199. }
  9200. }
  9201. if(scale.y < 0){
  9202. matrix.unshift(row);
  9203. } else {
  9204. matrix.push(row);
  9205. }
  9206. }
  9207. this.updateMaxValue();
  9208. this.updateMinValue();
  9209. this.update();
  9210. };
  9211. },{"../math/Vec3":43,"../utils/Utils":66,"./ConvexPolyhedron":51,"./Shape":56}],54:[function(require,module,exports){
  9212. module.exports = Particle;
  9213. var Shape = require('./Shape');
  9214. var Vec3 = require('../math/Vec3');
  9215. /**
  9216. * Particle shape.
  9217. * @class Particle
  9218. * @constructor
  9219. * @author schteppe
  9220. * @extends Shape
  9221. */
  9222. function Particle(){
  9223. Shape.call(this);
  9224. this.type = Shape.types.PARTICLE;
  9225. }
  9226. Particle.prototype = new Shape();
  9227. Particle.prototype.constructor = Particle;
  9228. /**
  9229. * @method calculateLocalInertia
  9230. * @param {Number} mass
  9231. * @param {Vec3} target
  9232. * @return {Vec3}
  9233. */
  9234. Particle.prototype.calculateLocalInertia = function(mass,target){
  9235. target = target || new Vec3();
  9236. target.set(0, 0, 0);
  9237. return target;
  9238. };
  9239. Particle.prototype.volume = function(){
  9240. return 0;
  9241. };
  9242. Particle.prototype.updateBoundingSphereRadius = function(){
  9243. this.boundingSphereRadius = 0;
  9244. };
  9245. Particle.prototype.calculateWorldAABB = function(pos,quat,min,max){
  9246. // Get each axis max
  9247. min.copy(pos);
  9248. max.copy(pos);
  9249. };
  9250. },{"../math/Vec3":43,"./Shape":56}],55:[function(require,module,exports){
  9251. module.exports = Plane;
  9252. var Shape = require('./Shape');
  9253. var Vec3 = require('../math/Vec3');
  9254. /**
  9255. * 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.
  9256. * @class Plane
  9257. * @constructor
  9258. * @extends Shape
  9259. * @author schteppe
  9260. */
  9261. function Plane(){
  9262. Shape.call(this);
  9263. this.type = Shape.types.PLANE;
  9264. // World oriented normal
  9265. this.worldNormal = new Vec3();
  9266. this.worldNormalNeedsUpdate = true;
  9267. this.boundingSphereRadius = Number.MAX_VALUE;
  9268. }
  9269. Plane.prototype = new Shape();
  9270. Plane.prototype.constructor = Plane;
  9271. Plane.prototype.computeWorldNormal = function(quat){
  9272. var n = this.worldNormal;
  9273. n.set(0,0,1);
  9274. quat.vmult(n,n);
  9275. this.worldNormalNeedsUpdate = false;
  9276. };
  9277. Plane.prototype.calculateLocalInertia = function(mass,target){
  9278. target = target || new Vec3();
  9279. return target;
  9280. };
  9281. Plane.prototype.volume = function(){
  9282. return Number.MAX_VALUE; // The plane is infinite...
  9283. };
  9284. var tempNormal = new Vec3();
  9285. Plane.prototype.calculateWorldAABB = function(pos, quat, min, max){
  9286. // The plane AABB is infinite, except if the normal is pointing along any axis
  9287. tempNormal.set(0,0,1); // Default plane normal is z
  9288. quat.vmult(tempNormal,tempNormal);
  9289. var maxVal = Number.MAX_VALUE;
  9290. min.set(-maxVal, -maxVal, -maxVal);
  9291. max.set(maxVal, maxVal, maxVal);
  9292. if(tempNormal.x === 1){ max.x = pos.x; }
  9293. if(tempNormal.y === 1){ max.y = pos.y; }
  9294. if(tempNormal.z === 1){ max.z = pos.z; }
  9295. if(tempNormal.x === -1){ min.x = pos.x; }
  9296. if(tempNormal.y === -1){ min.y = pos.y; }
  9297. if(tempNormal.z === -1){ min.z = pos.z; }
  9298. };
  9299. Plane.prototype.updateBoundingSphereRadius = function(){
  9300. this.boundingSphereRadius = Number.MAX_VALUE;
  9301. };
  9302. },{"../math/Vec3":43,"./Shape":56}],56:[function(require,module,exports){
  9303. module.exports = Shape;
  9304. var Shape = require('./Shape');
  9305. var Vec3 = require('../math/Vec3');
  9306. var Quaternion = require('../math/Quaternion');
  9307. var Material = require('../material/Material');
  9308. /**
  9309. * Base class for shapes
  9310. * @class Shape
  9311. * @constructor
  9312. * @author schteppe
  9313. * @todo Should have a mechanism for caching bounding sphere radius instead of calculating it each time
  9314. */
  9315. function Shape(){
  9316. /**
  9317. * Identifyer of the Shape.
  9318. * @property {number} id
  9319. */
  9320. this.id = Shape.idCounter++;
  9321. /**
  9322. * The type of this shape. Must be set to an int > 0 by subclasses.
  9323. * @property type
  9324. * @type {Number}
  9325. * @see Shape.types
  9326. */
  9327. this.type = 0;
  9328. /**
  9329. * The local bounding sphere radius of this shape.
  9330. * @property {Number} boundingSphereRadius
  9331. */
  9332. this.boundingSphereRadius = 0;
  9333. /**
  9334. * Whether to produce contact forces when in contact with other bodies. Note that contacts will be generated, but they will be disabled.
  9335. * @property {boolean} collisionResponse
  9336. */
  9337. this.collisionResponse = true;
  9338. /**
  9339. * @property {Material} material
  9340. */
  9341. this.material = null;
  9342. /**
  9343. * @property {Body} body
  9344. */
  9345. this.body = null;
  9346. }
  9347. Shape.prototype.constructor = Shape;
  9348. /**
  9349. * Computes the bounding sphere radius. The result is stored in the property .boundingSphereRadius
  9350. * @method updateBoundingSphereRadius
  9351. */
  9352. Shape.prototype.updateBoundingSphereRadius = function(){
  9353. throw "computeBoundingSphereRadius() not implemented for shape type "+this.type;
  9354. };
  9355. /**
  9356. * Get the volume of this shape
  9357. * @method volume
  9358. * @return {Number}
  9359. */
  9360. Shape.prototype.volume = function(){
  9361. throw "volume() not implemented for shape type "+this.type;
  9362. };
  9363. /**
  9364. * Calculates the inertia in the local frame for this shape.
  9365. * @method calculateLocalInertia
  9366. * @param {Number} mass
  9367. * @param {Vec3} target
  9368. * @see http://en.wikipedia.org/wiki/List_of_moments_of_inertia
  9369. */
  9370. Shape.prototype.calculateLocalInertia = function(mass,target){
  9371. throw "calculateLocalInertia() not implemented for shape type "+this.type;
  9372. };
  9373. Shape.idCounter = 0;
  9374. /**
  9375. * The available shape types.
  9376. * @static
  9377. * @property types
  9378. * @type {Object}
  9379. */
  9380. Shape.types = {
  9381. SPHERE:1,
  9382. PLANE:2,
  9383. BOX:4,
  9384. COMPOUND:8,
  9385. CONVEXPOLYHEDRON:16,
  9386. HEIGHTFIELD:32,
  9387. PARTICLE:64,
  9388. CYLINDER:128,
  9389. TRIMESH:256
  9390. };
  9391. },{"../material/Material":38,"../math/Quaternion":41,"../math/Vec3":43,"./Shape":56}],57:[function(require,module,exports){
  9392. module.exports = Sphere;
  9393. var Shape = require('./Shape');
  9394. var Vec3 = require('../math/Vec3');
  9395. /**
  9396. * Spherical shape
  9397. * @class Sphere
  9398. * @constructor
  9399. * @extends Shape
  9400. * @param {Number} radius The radius of the sphere, a non-negative number.
  9401. * @author schteppe / http://github.com/schteppe
  9402. */
  9403. function Sphere(radius){
  9404. Shape.call(this);
  9405. /**
  9406. * @property {Number} radius
  9407. */
  9408. this.radius = radius!==undefined ? Number(radius) : 1.0;
  9409. this.type = Shape.types.SPHERE;
  9410. if(this.radius < 0){
  9411. throw new Error('The sphere radius cannot be negative.');
  9412. }
  9413. this.updateBoundingSphereRadius();
  9414. }
  9415. Sphere.prototype = new Shape();
  9416. Sphere.prototype.constructor = Sphere;
  9417. Sphere.prototype.calculateLocalInertia = function(mass,target){
  9418. target = target || new Vec3();
  9419. var I = 2.0*mass*this.radius*this.radius/5.0;
  9420. target.x = I;
  9421. target.y = I;
  9422. target.z = I;
  9423. return target;
  9424. };
  9425. Sphere.prototype.volume = function(){
  9426. return 4.0 * Math.PI * this.radius / 3.0;
  9427. };
  9428. Sphere.prototype.updateBoundingSphereRadius = function(){
  9429. this.boundingSphereRadius = this.radius;
  9430. };
  9431. Sphere.prototype.calculateWorldAABB = function(pos,quat,min,max){
  9432. var r = this.radius;
  9433. var axes = ['x','y','z'];
  9434. for(var i=0; i<axes.length; i++){
  9435. var ax = axes[i];
  9436. min[ax] = pos[ax] - r;
  9437. max[ax] = pos[ax] + r;
  9438. }
  9439. };
  9440. },{"../math/Vec3":43,"./Shape":56}],58:[function(require,module,exports){
  9441. module.exports = Trimesh;
  9442. var Shape = require('./Shape');
  9443. var Vec3 = require('../math/Vec3');
  9444. var Quaternion = require('../math/Quaternion');
  9445. var Transform = require('../math/Transform');
  9446. var AABB = require('../collision/AABB');
  9447. var Octree = require('../utils/Octree');
  9448. /**
  9449. * @class Trimesh
  9450. * @constructor
  9451. * @param {array} vertices
  9452. * @param {array} indices
  9453. * @extends Shape
  9454. * @example
  9455. * // How to make a mesh with a single triangle
  9456. * var vertices = [
  9457. * 0, 0, 0, // vertex 0
  9458. * 1, 0, 0, // vertex 1
  9459. * 0, 1, 0 // vertex 2
  9460. * ];
  9461. * var indices = [
  9462. * 0, 1, 2 // triangle 0
  9463. * ];
  9464. * var trimeshShape = new Trimesh(vertices, indices);
  9465. */
  9466. function Trimesh(vertices, indices) {
  9467. Shape.call(this);
  9468. this.type = Shape.types.TRIMESH;
  9469. /**
  9470. * @property vertices
  9471. * @type {Array}
  9472. */
  9473. this.vertices = new Float32Array(vertices);
  9474. /**
  9475. * Array of integers, indicating which vertices each triangle consists of. The length of this array is thus 3 times the number of triangles.
  9476. * @property indices
  9477. * @type {Array}
  9478. */
  9479. this.indices = new Int16Array(indices);
  9480. /**
  9481. * The normals data.
  9482. * @property normals
  9483. * @type {Array}
  9484. */
  9485. this.normals = new Float32Array(indices.length);
  9486. /**
  9487. * The local AABB of the mesh.
  9488. * @property aabb
  9489. * @type {Array}
  9490. */
  9491. this.aabb = new AABB();
  9492. /**
  9493. * References to vertex pairs, making up all unique edges in the trimesh.
  9494. * @property {array} edges
  9495. */
  9496. this.edges = null;
  9497. /**
  9498. * Local scaling of the mesh. Use .setScale() to set it.
  9499. * @property {Vec3} scale
  9500. */
  9501. this.scale = new Vec3(1, 1, 1);
  9502. /**
  9503. * The indexed triangles. Use .updateTree() to update it.
  9504. * @property {Octree} tree
  9505. */
  9506. this.tree = new Octree();
  9507. this.updateEdges();
  9508. this.updateNormals();
  9509. this.updateAABB();
  9510. this.updateBoundingSphereRadius();
  9511. this.updateTree();
  9512. }
  9513. Trimesh.prototype = new Shape();
  9514. Trimesh.prototype.constructor = Trimesh;
  9515. var computeNormals_n = new Vec3();
  9516. /**
  9517. * @method updateTree
  9518. */
  9519. Trimesh.prototype.updateTree = function(){
  9520. var tree = this.tree;
  9521. tree.reset();
  9522. tree.aabb.copy(this.aabb);
  9523. var scale = this.scale; // The local mesh AABB is scaled, but the octree AABB should be unscaled
  9524. tree.aabb.lowerBound.x *= 1 / scale.x;
  9525. tree.aabb.lowerBound.y *= 1 / scale.y;
  9526. tree.aabb.lowerBound.z *= 1 / scale.z;
  9527. tree.aabb.upperBound.x *= 1 / scale.x;
  9528. tree.aabb.upperBound.y *= 1 / scale.y;
  9529. tree.aabb.upperBound.z *= 1 / scale.z;
  9530. // Insert all triangles
  9531. var triangleAABB = new AABB();
  9532. var a = new Vec3();
  9533. var b = new Vec3();
  9534. var c = new Vec3();
  9535. var points = [a, b, c];
  9536. for (var i = 0; i < this.indices.length / 3; i++) {
  9537. //this.getTriangleVertices(i, a, b, c);
  9538. // Get unscaled triangle verts
  9539. var i3 = i * 3;
  9540. this._getUnscaledVertex(this.indices[i3], a);
  9541. this._getUnscaledVertex(this.indices[i3 + 1], b);
  9542. this._getUnscaledVertex(this.indices[i3 + 2], c);
  9543. triangleAABB.setFromPoints(points);
  9544. tree.insert(triangleAABB, i);
  9545. }
  9546. tree.removeEmptyNodes();
  9547. };
  9548. var unscaledAABB = new AABB();
  9549. /**
  9550. * Get triangles in a local AABB from the trimesh.
  9551. * @method getTrianglesInAABB
  9552. * @param {AABB} aabb
  9553. * @param {array} result An array of integers, referencing the queried triangles.
  9554. */
  9555. Trimesh.prototype.getTrianglesInAABB = function(aabb, result){
  9556. unscaledAABB.copy(aabb);
  9557. // Scale it to local
  9558. var scale = this.scale;
  9559. var isx = scale.x;
  9560. var isy = scale.y;
  9561. var isz = scale.z;
  9562. var l = unscaledAABB.lowerBound;
  9563. var u = unscaledAABB.upperBound;
  9564. l.x /= isx;
  9565. l.y /= isy;
  9566. l.z /= isz;
  9567. u.x /= isx;
  9568. u.y /= isy;
  9569. u.z /= isz;
  9570. return this.tree.aabbQuery(unscaledAABB, result);
  9571. };
  9572. /**
  9573. * @method setScale
  9574. * @param {Vec3} scale
  9575. */
  9576. Trimesh.prototype.setScale = function(scale){
  9577. var wasUniform = this.scale.x === this.scale.y === this.scale.z;
  9578. var isUniform = scale.x === scale.y === scale.z;
  9579. if(!(wasUniform && isUniform)){
  9580. // Non-uniform scaling. Need to update normals.
  9581. this.updateNormals();
  9582. }
  9583. this.scale.copy(scale);
  9584. this.updateAABB();
  9585. this.updateBoundingSphereRadius();
  9586. };
  9587. /**
  9588. * Compute the normals of the faces. Will save in the .normals array.
  9589. * @method updateNormals
  9590. */
  9591. Trimesh.prototype.updateNormals = function(){
  9592. var n = computeNormals_n;
  9593. // Generate normals
  9594. var normals = this.normals;
  9595. for(var i=0; i < this.indices.length / 3; i++){
  9596. var i3 = i * 3;
  9597. var a = this.indices[i3],
  9598. b = this.indices[i3 + 1],
  9599. c = this.indices[i3 + 2];
  9600. this.getVertex(a, va);
  9601. this.getVertex(b, vb);
  9602. this.getVertex(c, vc);
  9603. Trimesh.computeNormal(vb, va, vc, n);
  9604. normals[i3] = n.x;
  9605. normals[i3 + 1] = n.y;
  9606. normals[i3 + 2] = n.z;
  9607. }
  9608. };
  9609. /**
  9610. * Update the .edges property
  9611. * @method updateEdges
  9612. */
  9613. Trimesh.prototype.updateEdges = function(){
  9614. var edges = {};
  9615. var add = function(indexA, indexB){
  9616. var key = a < b ? a + '_' + b : b + '_' + a;
  9617. edges[key] = true;
  9618. };
  9619. for(var i=0; i < this.indices.length / 3; i++){
  9620. var i3 = i * 3;
  9621. var a = this.indices[i3],
  9622. b = this.indices[i3 + 1],
  9623. c = this.indices[i3 + 2];
  9624. add(a,b);
  9625. add(b,c);
  9626. add(c,a);
  9627. }
  9628. var keys = Object.keys(edges);
  9629. this.edges = new Int16Array(keys.length * 2);
  9630. for (var i = 0; i < keys.length; i++) {
  9631. var indices = keys[i].split('_');
  9632. this.edges[2 * i] = parseInt(indices[0], 10);
  9633. this.edges[2 * i + 1] = parseInt(indices[1], 10);
  9634. }
  9635. };
  9636. /**
  9637. * Get an edge vertex
  9638. * @method getEdgeVertex
  9639. * @param {number} edgeIndex
  9640. * @param {number} firstOrSecond 0 or 1, depending on which one of the vertices you need.
  9641. * @param {Vec3} vertexStore Where to store the result
  9642. */
  9643. Trimesh.prototype.getEdgeVertex = function(edgeIndex, firstOrSecond, vertexStore){
  9644. var vertexIndex = this.edges[edgeIndex * 2 + (firstOrSecond ? 1 : 0)];
  9645. this.getVertex(vertexIndex, vertexStore);
  9646. };
  9647. var getEdgeVector_va = new Vec3();
  9648. var getEdgeVector_vb = new Vec3();
  9649. /**
  9650. * Get a vector along an edge.
  9651. * @method getEdgeVector
  9652. * @param {number} edgeIndex
  9653. * @param {Vec3} vectorStore
  9654. */
  9655. Trimesh.prototype.getEdgeVector = function(edgeIndex, vectorStore){
  9656. var va = getEdgeVector_va;
  9657. var vb = getEdgeVector_vb;
  9658. this.getEdgeVertex(edgeIndex, 0, va);
  9659. this.getEdgeVertex(edgeIndex, 1, vb);
  9660. vb.vsub(va, vectorStore);
  9661. };
  9662. /**
  9663. * Get face normal given 3 vertices
  9664. * @static
  9665. * @method computeNormal
  9666. * @param {Vec3} va
  9667. * @param {Vec3} vb
  9668. * @param {Vec3} vc
  9669. * @param {Vec3} target
  9670. */
  9671. var cb = new Vec3();
  9672. var ab = new Vec3();
  9673. Trimesh.computeNormal = function ( va, vb, vc, target ) {
  9674. vb.vsub(va,ab);
  9675. vc.vsub(vb,cb);
  9676. cb.cross(ab,target);
  9677. if ( !target.isZero() ) {
  9678. target.normalize();
  9679. }
  9680. };
  9681. var va = new Vec3();
  9682. var vb = new Vec3();
  9683. var vc = new Vec3();
  9684. /**
  9685. * Get vertex i.
  9686. * @method getVertex
  9687. * @param {number} i
  9688. * @param {Vec3} out
  9689. * @return {Vec3} The "out" vector object
  9690. */
  9691. Trimesh.prototype.getVertex = function(i, out){
  9692. var scale = this.scale;
  9693. this._getUnscaledVertex(i, out);
  9694. out.x *= scale.x;
  9695. out.y *= scale.y;
  9696. out.z *= scale.z;
  9697. return out;
  9698. };
  9699. /**
  9700. * Get raw vertex i
  9701. * @private
  9702. * @method _getUnscaledVertex
  9703. * @param {number} i
  9704. * @param {Vec3} out
  9705. * @return {Vec3} The "out" vector object
  9706. */
  9707. Trimesh.prototype._getUnscaledVertex = function(i, out){
  9708. var i3 = i * 3;
  9709. var vertices = this.vertices;
  9710. return out.set(
  9711. vertices[i3],
  9712. vertices[i3 + 1],
  9713. vertices[i3 + 2]
  9714. );
  9715. };
  9716. /**
  9717. * Get a vertex from the trimesh,transformed by the given position and quaternion.
  9718. * @method getWorldVertex
  9719. * @param {number} i
  9720. * @param {Vec3} pos
  9721. * @param {Quaternion} quat
  9722. * @param {Vec3} out
  9723. * @return {Vec3} The "out" vector object
  9724. */
  9725. Trimesh.prototype.getWorldVertex = function(i, pos, quat, out){
  9726. this.getVertex(i, out);
  9727. Transform.pointToWorldFrame(pos, quat, out, out);
  9728. return out;
  9729. };
  9730. /**
  9731. * Get the three vertices for triangle i.
  9732. * @method getTriangleVertices
  9733. * @param {number} i
  9734. * @param {Vec3} a
  9735. * @param {Vec3} b
  9736. * @param {Vec3} c
  9737. */
  9738. Trimesh.prototype.getTriangleVertices = function(i, a, b, c){
  9739. var i3 = i * 3;
  9740. this.getVertex(this.indices[i3], a);
  9741. this.getVertex(this.indices[i3 + 1], b);
  9742. this.getVertex(this.indices[i3 + 2], c);
  9743. };
  9744. /**
  9745. * Compute the normal of triangle i.
  9746. * @method getNormal
  9747. * @param {Number} i
  9748. * @param {Vec3} target
  9749. * @return {Vec3} The "target" vector object
  9750. */
  9751. Trimesh.prototype.getNormal = function(i, target){
  9752. var i3 = i * 3;
  9753. return target.set(
  9754. this.normals[i3],
  9755. this.normals[i3 + 1],
  9756. this.normals[i3 + 2]
  9757. );
  9758. };
  9759. var cli_aabb = new AABB();
  9760. /**
  9761. * @method calculateLocalInertia
  9762. * @param {Number} mass
  9763. * @param {Vec3} target
  9764. * @return {Vec3} The "target" vector object
  9765. */
  9766. Trimesh.prototype.calculateLocalInertia = function(mass,target){
  9767. // Approximate with box inertia
  9768. // Exact inertia calculation is overkill, but see http://geometrictools.com/Documentation/PolyhedralMassProperties.pdf for the correct way to do it
  9769. this.computeLocalAABB(cli_aabb);
  9770. var x = cli_aabb.upperBound.x - cli_aabb.lowerBound.x,
  9771. y = cli_aabb.upperBound.y - cli_aabb.lowerBound.y,
  9772. z = cli_aabb.upperBound.z - cli_aabb.lowerBound.z;
  9773. return target.set(
  9774. 1.0 / 12.0 * mass * ( 2*y*2*y + 2*z*2*z ),
  9775. 1.0 / 12.0 * mass * ( 2*x*2*x + 2*z*2*z ),
  9776. 1.0 / 12.0 * mass * ( 2*y*2*y + 2*x*2*x )
  9777. );
  9778. };
  9779. var computeLocalAABB_worldVert = new Vec3();
  9780. /**
  9781. * Compute the local AABB for the trimesh
  9782. * @method computeLocalAABB
  9783. * @param {AABB} aabb
  9784. */
  9785. Trimesh.prototype.computeLocalAABB = function(aabb){
  9786. var l = aabb.lowerBound,
  9787. u = aabb.upperBound,
  9788. n = this.vertices.length,
  9789. vertices = this.vertices,
  9790. v = computeLocalAABB_worldVert;
  9791. this.getVertex(0, v);
  9792. l.copy(v);
  9793. u.copy(v);
  9794. for(var i=0; i !== n; i++){
  9795. this.getVertex(i, v);
  9796. if(v.x < l.x){
  9797. l.x = v.x;
  9798. } else if(v.x > u.x){
  9799. u.x = v.x;
  9800. }
  9801. if(v.y < l.y){
  9802. l.y = v.y;
  9803. } else if(v.y > u.y){
  9804. u.y = v.y;
  9805. }
  9806. if(v.z < l.z){
  9807. l.z = v.z;
  9808. } else if(v.z > u.z){
  9809. u.z = v.z;
  9810. }
  9811. }
  9812. };
  9813. /**
  9814. * Update the .aabb property
  9815. * @method updateAABB
  9816. */
  9817. Trimesh.prototype.updateAABB = function(){
  9818. this.computeLocalAABB(this.aabb);
  9819. };
  9820. /**
  9821. * Will update the .boundingSphereRadius property
  9822. * @method updateBoundingSphereRadius
  9823. */
  9824. Trimesh.prototype.updateBoundingSphereRadius = function(){
  9825. // Assume points are distributed with local (0,0,0) as center
  9826. var max2 = 0;
  9827. var vertices = this.vertices;
  9828. var v = new Vec3();
  9829. for(var i=0, N=vertices.length / 3; i !== N; i++) {
  9830. this.getVertex(i, v);
  9831. var norm2 = v.norm2();
  9832. if(norm2 > max2){
  9833. max2 = norm2;
  9834. }
  9835. }
  9836. this.boundingSphereRadius = Math.sqrt(max2);
  9837. };
  9838. var tempWorldVertex = new Vec3();
  9839. var calculateWorldAABB_frame = new Transform();
  9840. var calculateWorldAABB_aabb = new AABB();
  9841. /**
  9842. * @method calculateWorldAABB
  9843. * @param {Vec3} pos
  9844. * @param {Quaternion} quat
  9845. * @param {Vec3} min
  9846. * @param {Vec3} max
  9847. */
  9848. Trimesh.prototype.calculateWorldAABB = function(pos,quat,min,max){
  9849. /*
  9850. var n = this.vertices.length / 3,
  9851. verts = this.vertices;
  9852. var minx,miny,minz,maxx,maxy,maxz;
  9853. var v = tempWorldVertex;
  9854. for(var i=0; i<n; i++){
  9855. this.getVertex(i, v);
  9856. quat.vmult(v, v);
  9857. pos.vadd(v, v);
  9858. if (v.x < minx || minx===undefined){
  9859. minx = v.x;
  9860. } else if(v.x > maxx || maxx===undefined){
  9861. maxx = v.x;
  9862. }
  9863. if (v.y < miny || miny===undefined){
  9864. miny = v.y;
  9865. } else if(v.y > maxy || maxy===undefined){
  9866. maxy = v.y;
  9867. }
  9868. if (v.z < minz || minz===undefined){
  9869. minz = v.z;
  9870. } else if(v.z > maxz || maxz===undefined){
  9871. maxz = v.z;
  9872. }
  9873. }
  9874. min.set(minx,miny,minz);
  9875. max.set(maxx,maxy,maxz);
  9876. */
  9877. // Faster approximation using local AABB
  9878. var frame = calculateWorldAABB_frame;
  9879. var result = calculateWorldAABB_aabb;
  9880. frame.position = pos;
  9881. frame.quaternion = quat;
  9882. this.aabb.toWorldFrame(frame, result);
  9883. min.copy(result.lowerBound);
  9884. max.copy(result.upperBound);
  9885. };
  9886. /**
  9887. * Get approximate volume
  9888. * @method volume
  9889. * @return {Number}
  9890. */
  9891. Trimesh.prototype.volume = function(){
  9892. return 4.0 * Math.PI * this.boundingSphereRadius / 3.0;
  9893. };
  9894. /**
  9895. * Create a Trimesh instance, shaped as a torus.
  9896. * @static
  9897. * @method createTorus
  9898. * @param {number} [radius=1]
  9899. * @param {number} [tube=0.5]
  9900. * @param {number} [radialSegments=8]
  9901. * @param {number} [tubularSegments=6]
  9902. * @param {number} [arc=6.283185307179586]
  9903. * @return {Trimesh} A torus
  9904. */
  9905. Trimesh.createTorus = function (radius, tube, radialSegments, tubularSegments, arc) {
  9906. radius = radius || 1;
  9907. tube = tube || 0.5;
  9908. radialSegments = radialSegments || 8;
  9909. tubularSegments = tubularSegments || 6;
  9910. arc = arc || Math.PI * 2;
  9911. var vertices = [];
  9912. var indices = [];
  9913. for ( var j = 0; j <= radialSegments; j ++ ) {
  9914. for ( var i = 0; i <= tubularSegments; i ++ ) {
  9915. var u = i / tubularSegments * arc;
  9916. var v = j / radialSegments * Math.PI * 2;
  9917. var x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
  9918. var y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
  9919. var z = tube * Math.sin( v );
  9920. vertices.push( x, y, z );
  9921. }
  9922. }
  9923. for ( var j = 1; j <= radialSegments; j ++ ) {
  9924. for ( var i = 1; i <= tubularSegments; i ++ ) {
  9925. var a = ( tubularSegments + 1 ) * j + i - 1;
  9926. var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
  9927. var c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
  9928. var d = ( tubularSegments + 1 ) * j + i;
  9929. indices.push(a, b, d);
  9930. indices.push(b, c, d);
  9931. }
  9932. }
  9933. return new Trimesh(vertices, indices);
  9934. };
  9935. },{"../collision/AABB":15,"../math/Quaternion":41,"../math/Transform":42,"../math/Vec3":43,"../utils/Octree":63,"./Shape":56}],59:[function(require,module,exports){
  9936. module.exports = GSSolver;
  9937. var Vec3 = require('../math/Vec3');
  9938. var Quaternion = require('../math/Quaternion');
  9939. var Solver = require('./Solver');
  9940. /**
  9941. * Constraint equation Gauss-Seidel solver.
  9942. * @class GSSolver
  9943. * @constructor
  9944. * @todo The spook parameters should be specified for each constraint, not globally.
  9945. * @author schteppe / https://github.com/schteppe
  9946. * @see https://www8.cs.umu.se/kurser/5DV058/VT09/lectures/spooknotes.pdf
  9947. * @extends Solver
  9948. */
  9949. function GSSolver(){
  9950. Solver.call(this);
  9951. /**
  9952. * 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.
  9953. * @property iterations
  9954. * @type {Number}
  9955. * @todo write more about solver and iterations in the wiki
  9956. */
  9957. this.iterations = 10;
  9958. /**
  9959. * When tolerance is reached, the system is assumed to be converged.
  9960. * @property tolerance
  9961. * @type {Number}
  9962. */
  9963. this.tolerance = 1e-7;
  9964. }
  9965. GSSolver.prototype = new Solver();
  9966. var GSSolver_solve_lambda = []; // Just temporary number holders that we want to reuse each solve.
  9967. var GSSolver_solve_invCs = [];
  9968. var GSSolver_solve_Bs = [];
  9969. GSSolver.prototype.solve = function(dt,world){
  9970. var iter = 0,
  9971. maxIter = this.iterations,
  9972. tolSquared = this.tolerance*this.tolerance,
  9973. equations = this.equations,
  9974. Neq = equations.length,
  9975. bodies = world.bodies,
  9976. Nbodies = bodies.length,
  9977. h = dt,
  9978. q, B, invC, deltalambda, deltalambdaTot, GWlambda, lambdaj;
  9979. // Update solve mass
  9980. if(Neq !== 0){
  9981. for(var i=0; i!==Nbodies; i++){
  9982. bodies[i].updateSolveMassProperties();
  9983. }
  9984. }
  9985. // Things that does not change during iteration can be computed once
  9986. var invCs = GSSolver_solve_invCs,
  9987. Bs = GSSolver_solve_Bs,
  9988. lambda = GSSolver_solve_lambda;
  9989. invCs.length = Neq;
  9990. Bs.length = Neq;
  9991. lambda.length = Neq;
  9992. for(var i=0; i!==Neq; i++){
  9993. var c = equations[i];
  9994. lambda[i] = 0.0;
  9995. Bs[i] = c.computeB(h);
  9996. invCs[i] = 1.0 / c.computeC();
  9997. }
  9998. if(Neq !== 0){
  9999. // Reset vlambda
  10000. for(var i=0; i!==Nbodies; i++){
  10001. var b=bodies[i],
  10002. vlambda=b.vlambda,
  10003. wlambda=b.wlambda;
  10004. vlambda.set(0,0,0);
  10005. wlambda.set(0,0,0);
  10006. }
  10007. // Iterate over equations
  10008. for(iter=0; iter!==maxIter; iter++){
  10009. // Accumulate the total error for each iteration.
  10010. deltalambdaTot = 0.0;
  10011. for(var j=0; j!==Neq; j++){
  10012. var c = equations[j];
  10013. // Compute iteration
  10014. B = Bs[j];
  10015. invC = invCs[j];
  10016. lambdaj = lambda[j];
  10017. GWlambda = c.computeGWlambda();
  10018. deltalambda = invC * ( B - GWlambda - c.eps * lambdaj );
  10019. // Clamp if we are not within the min/max interval
  10020. if(lambdaj + deltalambda < c.minForce){
  10021. deltalambda = c.minForce - lambdaj;
  10022. } else if(lambdaj + deltalambda > c.maxForce){
  10023. deltalambda = c.maxForce - lambdaj;
  10024. }
  10025. lambda[j] += deltalambda;
  10026. deltalambdaTot += deltalambda > 0.0 ? deltalambda : -deltalambda; // abs(deltalambda)
  10027. c.addToWlambda(deltalambda);
  10028. }
  10029. // If the total error is small enough - stop iterate
  10030. if(deltalambdaTot*deltalambdaTot < tolSquared){
  10031. break;
  10032. }
  10033. }
  10034. // Add result to velocity
  10035. for(var i=0; i!==Nbodies; i++){
  10036. var b=bodies[i],
  10037. v=b.velocity,
  10038. w=b.angularVelocity;
  10039. b.vlambda.vmul(b.linearFactor, b.vlambda);
  10040. v.vadd(b.vlambda, v);
  10041. b.wlambda.vmul(b.angularFactor, b.wlambda);
  10042. w.vadd(b.wlambda, w);
  10043. }
  10044. // Set the .multiplier property of each equation
  10045. var l = equations.length;
  10046. var invDt = 1 / h;
  10047. while(l--){
  10048. equations[l].multiplier = lambda[l] * invDt;
  10049. }
  10050. }
  10051. return iter;
  10052. };
  10053. },{"../math/Quaternion":41,"../math/Vec3":43,"./Solver":60}],60:[function(require,module,exports){
  10054. module.exports = Solver;
  10055. /**
  10056. * Constraint equation solver base class.
  10057. * @class Solver
  10058. * @constructor
  10059. * @author schteppe / https://github.com/schteppe
  10060. */
  10061. function Solver(){
  10062. /**
  10063. * All equations to be solved
  10064. * @property {Array} equations
  10065. */
  10066. this.equations = [];
  10067. }
  10068. /**
  10069. * Should be implemented in subclasses!
  10070. * @method solve
  10071. * @param {Number} dt
  10072. * @param {World} world
  10073. */
  10074. Solver.prototype.solve = function(dt,world){
  10075. // Should return the number of iterations done!
  10076. return 0;
  10077. };
  10078. /**
  10079. * Add an equation
  10080. * @method addEquation
  10081. * @param {Equation} eq
  10082. */
  10083. Solver.prototype.addEquation = function(eq){
  10084. if (eq.enabled) {
  10085. this.equations.push(eq);
  10086. }
  10087. };
  10088. /**
  10089. * Remove an equation
  10090. * @method removeEquation
  10091. * @param {Equation} eq
  10092. */
  10093. Solver.prototype.removeEquation = function(eq){
  10094. var eqs = this.equations;
  10095. var i = eqs.indexOf(eq);
  10096. if(i !== -1){
  10097. eqs.splice(i,1);
  10098. }
  10099. };
  10100. /**
  10101. * Add all equations
  10102. * @method removeAllEquations
  10103. */
  10104. Solver.prototype.removeAllEquations = function(){
  10105. this.equations.length = 0;
  10106. };
  10107. },{}],61:[function(require,module,exports){
  10108. module.exports = SplitSolver;
  10109. var Vec3 = require('../math/Vec3');
  10110. var Quaternion = require('../math/Quaternion');
  10111. var Solver = require('./Solver');
  10112. var Body = require('../objects/Body');
  10113. /**
  10114. * Splits the equations into islands and solves them independently. Can improve performance.
  10115. * @class SplitSolver
  10116. * @constructor
  10117. * @extends Solver
  10118. * @param {Solver} subsolver
  10119. */
  10120. function SplitSolver(subsolver){
  10121. Solver.call(this);
  10122. this.iterations = 10;
  10123. this.tolerance = 1e-7;
  10124. this.subsolver = subsolver;
  10125. this.nodes = [];
  10126. this.nodePool = [];
  10127. // Create needed nodes, reuse if possible
  10128. while(this.nodePool.length < 128){
  10129. this.nodePool.push(this.createNode());
  10130. }
  10131. }
  10132. SplitSolver.prototype = new Solver();
  10133. // Returns the number of subsystems
  10134. var SplitSolver_solve_nodes = []; // All allocated node objects
  10135. var SplitSolver_solve_nodePool = []; // All allocated node objects
  10136. var SplitSolver_solve_eqs = []; // Temp array
  10137. var SplitSolver_solve_bds = []; // Temp array
  10138. var SplitSolver_solve_dummyWorld = {bodies:[]}; // Temp object
  10139. var STATIC = Body.STATIC;
  10140. function getUnvisitedNode(nodes){
  10141. var Nnodes = nodes.length;
  10142. for(var i=0; i!==Nnodes; i++){
  10143. var node = nodes[i];
  10144. if(!node.visited && !(node.body.type & STATIC)){
  10145. return node;
  10146. }
  10147. }
  10148. return false;
  10149. }
  10150. var queue = [];
  10151. function bfs(root,visitFunc,bds,eqs){
  10152. queue.push(root);
  10153. root.visited = true;
  10154. visitFunc(root,bds,eqs);
  10155. while(queue.length) {
  10156. var node = queue.pop();
  10157. // Loop over unvisited child nodes
  10158. var child;
  10159. while((child = getUnvisitedNode(node.children))) {
  10160. child.visited = true;
  10161. visitFunc(child,bds,eqs);
  10162. queue.push(child);
  10163. }
  10164. }
  10165. }
  10166. function visitFunc(node,bds,eqs){
  10167. bds.push(node.body);
  10168. var Neqs = node.eqs.length;
  10169. for(var i=0; i!==Neqs; i++){
  10170. var eq = node.eqs[i];
  10171. if(eqs.indexOf(eq) === -1){
  10172. eqs.push(eq);
  10173. }
  10174. }
  10175. }
  10176. SplitSolver.prototype.createNode = function(){
  10177. return { body:null, children:[], eqs:[], visited:false };
  10178. };
  10179. /**
  10180. * Solve the subsystems
  10181. * @method solve
  10182. * @param {Number} dt
  10183. * @param {World} world
  10184. */
  10185. SplitSolver.prototype.solve = function(dt,world){
  10186. var nodes=SplitSolver_solve_nodes,
  10187. nodePool=this.nodePool,
  10188. bodies=world.bodies,
  10189. equations=this.equations,
  10190. Neq=equations.length,
  10191. Nbodies=bodies.length,
  10192. subsolver=this.subsolver;
  10193. // Create needed nodes, reuse if possible
  10194. while(nodePool.length < Nbodies){
  10195. nodePool.push(this.createNode());
  10196. }
  10197. nodes.length = Nbodies;
  10198. for (var i = 0; i < Nbodies; i++) {
  10199. nodes[i] = nodePool[i];
  10200. }
  10201. // Reset node values
  10202. for(var i=0; i!==Nbodies; i++){
  10203. var node = nodes[i];
  10204. node.body = bodies[i];
  10205. node.children.length = 0;
  10206. node.eqs.length = 0;
  10207. node.visited = false;
  10208. }
  10209. for(var k=0; k!==Neq; k++){
  10210. var eq=equations[k],
  10211. i=bodies.indexOf(eq.bi),
  10212. j=bodies.indexOf(eq.bj),
  10213. ni=nodes[i],
  10214. nj=nodes[j];
  10215. ni.children.push(nj);
  10216. ni.eqs.push(eq);
  10217. nj.children.push(ni);
  10218. nj.eqs.push(eq);
  10219. }
  10220. var child, n=0, eqs=SplitSolver_solve_eqs;
  10221. subsolver.tolerance = this.tolerance;
  10222. subsolver.iterations = this.iterations;
  10223. var dummyWorld = SplitSolver_solve_dummyWorld;
  10224. while((child = getUnvisitedNode(nodes))){
  10225. eqs.length = 0;
  10226. dummyWorld.bodies.length = 0;
  10227. bfs(child, visitFunc, dummyWorld.bodies, eqs);
  10228. var Neqs = eqs.length;
  10229. eqs = eqs.sort(sortById);
  10230. for(var i=0; i!==Neqs; i++){
  10231. subsolver.addEquation(eqs[i]);
  10232. }
  10233. var iter = subsolver.solve(dt,dummyWorld);
  10234. subsolver.removeAllEquations();
  10235. n++;
  10236. }
  10237. return n;
  10238. };
  10239. function sortById(a, b){
  10240. return b.id - a.id;
  10241. }
  10242. },{"../math/Quaternion":41,"../math/Vec3":43,"../objects/Body":44,"./Solver":60}],62:[function(require,module,exports){
  10243. /**
  10244. * Base class for objects that dispatches events.
  10245. * @class EventTarget
  10246. * @constructor
  10247. */
  10248. var EventTarget = function () {
  10249. };
  10250. module.exports = EventTarget;
  10251. EventTarget.prototype = {
  10252. constructor: EventTarget,
  10253. /**
  10254. * Add an event listener
  10255. * @method addEventListener
  10256. * @param {String} type
  10257. * @param {Function} listener
  10258. * @return {EventTarget} The self object, for chainability.
  10259. */
  10260. addEventListener: function ( type, listener ) {
  10261. if ( this._listeners === undefined ){ this._listeners = {}; }
  10262. var listeners = this._listeners;
  10263. if ( listeners[ type ] === undefined ) {
  10264. listeners[ type ] = [];
  10265. }
  10266. if ( listeners[ type ].indexOf( listener ) === - 1 ) {
  10267. listeners[ type ].push( listener );
  10268. }
  10269. return this;
  10270. },
  10271. /**
  10272. * Check if an event listener is added
  10273. * @method hasEventListener
  10274. * @param {String} type
  10275. * @param {Function} listener
  10276. * @return {Boolean}
  10277. */
  10278. hasEventListener: function ( type, listener ) {
  10279. if ( this._listeners === undefined ){ return false; }
  10280. var listeners = this._listeners;
  10281. if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) {
  10282. return true;
  10283. }
  10284. return false;
  10285. },
  10286. /**
  10287. * Check if any event listener of the given type is added
  10288. * @method hasAnyEventListener
  10289. * @param {String} type
  10290. * @return {Boolean}
  10291. */
  10292. hasAnyEventListener: function ( type ) {
  10293. if ( this._listeners === undefined ){ return false; }
  10294. var listeners = this._listeners;
  10295. return ( listeners[ type ] !== undefined );
  10296. },
  10297. /**
  10298. * Remove an event listener
  10299. * @method removeEventListener
  10300. * @param {String} type
  10301. * @param {Function} listener
  10302. * @return {EventTarget} The self object, for chainability.
  10303. */
  10304. removeEventListener: function ( type, listener ) {
  10305. if ( this._listeners === undefined ){ return this; }
  10306. var listeners = this._listeners;
  10307. if ( listeners[type] === undefined ){ return this; }
  10308. var index = listeners[ type ].indexOf( listener );
  10309. if ( index !== - 1 ) {
  10310. listeners[ type ].splice( index, 1 );
  10311. }
  10312. return this;
  10313. },
  10314. /**
  10315. * Emit an event.
  10316. * @method dispatchEvent
  10317. * @param {Object} event
  10318. * @param {String} event.type
  10319. * @return {EventTarget} The self object, for chainability.
  10320. */
  10321. dispatchEvent: function ( event ) {
  10322. if ( this._listeners === undefined ){ return this; }
  10323. var listeners = this._listeners;
  10324. var listenerArray = listeners[ event.type ];
  10325. if ( listenerArray !== undefined ) {
  10326. event.target = this;
  10327. for ( var i = 0, l = listenerArray.length; i < l; i ++ ) {
  10328. listenerArray[ i ].call( this, event );
  10329. }
  10330. }
  10331. return this;
  10332. }
  10333. };
  10334. },{}],63:[function(require,module,exports){
  10335. var AABB = require('../collision/AABB');
  10336. var Vec3 = require('../math/Vec3');
  10337. module.exports = Octree;
  10338. /**
  10339. * @class OctreeNode
  10340. * @param {object} [options]
  10341. * @param {Octree} [options.root]
  10342. * @param {AABB} [options.aabb]
  10343. */
  10344. function OctreeNode(options){
  10345. options = options || {};
  10346. /**
  10347. * The root node
  10348. * @property {OctreeNode} root
  10349. */
  10350. this.root = options.root || null;
  10351. /**
  10352. * Boundary of this node
  10353. * @property {AABB} aabb
  10354. */
  10355. this.aabb = options.aabb ? options.aabb.clone() : new AABB();
  10356. /**
  10357. * Contained data at the current node level.
  10358. * @property {Array} data
  10359. */
  10360. this.data = [];
  10361. /**
  10362. * Children to this node
  10363. * @property {Array} children
  10364. */
  10365. this.children = [];
  10366. }
  10367. /**
  10368. * @class Octree
  10369. * @param {AABB} aabb The total AABB of the tree
  10370. * @param {object} [options]
  10371. * @param {number} [options.maxDepth=8]
  10372. * @extends OctreeNode
  10373. */
  10374. function Octree(aabb, options){
  10375. options = options || {};
  10376. options.root = null;
  10377. options.aabb = aabb;
  10378. OctreeNode.call(this, options);
  10379. /**
  10380. * Maximum subdivision depth
  10381. * @property {number} maxDepth
  10382. */
  10383. this.maxDepth = typeof(options.maxDepth) !== 'undefined' ? options.maxDepth : 8;
  10384. }
  10385. Octree.prototype = new OctreeNode();
  10386. OctreeNode.prototype.reset = function(aabb, options){
  10387. this.children.length = this.data.length = 0;
  10388. };
  10389. /**
  10390. * Insert data into this node
  10391. * @method insert
  10392. * @param {AABB} aabb
  10393. * @param {object} elementData
  10394. * @return {boolean} True if successful, otherwise false
  10395. */
  10396. OctreeNode.prototype.insert = function(aabb, elementData, level){
  10397. var nodeData = this.data;
  10398. level = level || 0;
  10399. // Ignore objects that do not belong in this node
  10400. if (!this.aabb.contains(aabb)){
  10401. return false; // object cannot be added
  10402. }
  10403. var children = this.children;
  10404. if(level < (this.maxDepth || this.root.maxDepth)){
  10405. // Subdivide if there are no children yet
  10406. var subdivided = false;
  10407. if (!children.length){
  10408. this.subdivide();
  10409. subdivided = true;
  10410. }
  10411. // add to whichever node will accept it
  10412. for (var i = 0; i !== 8; i++) {
  10413. if (children[i].insert(aabb, elementData, level + 1)){
  10414. return true;
  10415. }
  10416. }
  10417. if(subdivided){
  10418. // No children accepted! Might as well just remove em since they contain none
  10419. children.length = 0;
  10420. }
  10421. }
  10422. // Too deep, or children didnt want it. add it in current node
  10423. nodeData.push(elementData);
  10424. return true;
  10425. };
  10426. var halfDiagonal = new Vec3();
  10427. /**
  10428. * Create 8 equally sized children nodes and put them in the .children array.
  10429. * @method subdivide
  10430. */
  10431. OctreeNode.prototype.subdivide = function() {
  10432. var aabb = this.aabb;
  10433. var l = aabb.lowerBound;
  10434. var u = aabb.upperBound;
  10435. var children = this.children;
  10436. children.push(
  10437. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,0,0) }) }),
  10438. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,0,0) }) }),
  10439. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,1,0) }) }),
  10440. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,1,1) }) }),
  10441. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,1,1) }) }),
  10442. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,0,1) }) }),
  10443. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(1,0,1) }) }),
  10444. new OctreeNode({ aabb: new AABB({ lowerBound: new Vec3(0,1,0) }) })
  10445. );
  10446. u.vsub(l, halfDiagonal);
  10447. halfDiagonal.scale(0.5, halfDiagonal);
  10448. var root = this.root || this;
  10449. for (var i = 0; i !== 8; i++) {
  10450. var child = children[i];
  10451. // Set current node as root
  10452. child.root = root;
  10453. // Compute bounds
  10454. var lowerBound = child.aabb.lowerBound;
  10455. lowerBound.x *= halfDiagonal.x;
  10456. lowerBound.y *= halfDiagonal.y;
  10457. lowerBound.z *= halfDiagonal.z;
  10458. lowerBound.vadd(l, lowerBound);
  10459. // Upper bound is always lower bound + halfDiagonal
  10460. lowerBound.vadd(halfDiagonal, child.aabb.upperBound);
  10461. }
  10462. };
  10463. /**
  10464. * Get all data, potentially within an AABB
  10465. * @method aabbQuery
  10466. * @param {AABB} aabb
  10467. * @param {array} result
  10468. * @return {array} The "result" object
  10469. */
  10470. OctreeNode.prototype.aabbQuery = function(aabb, result) {
  10471. var nodeData = this.data;
  10472. // abort if the range does not intersect this node
  10473. // if (!this.aabb.overlaps(aabb)){
  10474. // return result;
  10475. // }
  10476. // Add objects at this level
  10477. // Array.prototype.push.apply(result, nodeData);
  10478. // Add child data
  10479. // @todo unwrap recursion into a queue / loop, that's faster in JS
  10480. var children = this.children;
  10481. // for (var i = 0, N = this.children.length; i !== N; i++) {
  10482. // children[i].aabbQuery(aabb, result);
  10483. // }
  10484. var queue = [this];
  10485. while (queue.length) {
  10486. var node = queue.pop();
  10487. if (node.aabb.overlaps(aabb)){
  10488. Array.prototype.push.apply(result, node.data);
  10489. }
  10490. Array.prototype.push.apply(queue, node.children);
  10491. }
  10492. return result;
  10493. };
  10494. var tmpAABB = new AABB();
  10495. /**
  10496. * Get all data, potentially intersected by a ray.
  10497. * @method rayQuery
  10498. * @param {Ray} ray
  10499. * @param {Transform} treeTransform
  10500. * @param {array} result
  10501. * @return {array} The "result" object
  10502. */
  10503. OctreeNode.prototype.rayQuery = function(ray, treeTransform, result) {
  10504. // Use aabb query for now.
  10505. // @todo implement real ray query which needs less lookups
  10506. ray.getAABB(tmpAABB);
  10507. tmpAABB.toLocalFrame(treeTransform, tmpAABB);
  10508. this.aabbQuery(tmpAABB, result);
  10509. return result;
  10510. };
  10511. /**
  10512. * @method removeEmptyNodes
  10513. */
  10514. OctreeNode.prototype.removeEmptyNodes = function() {
  10515. var queue = [this];
  10516. while (queue.length) {
  10517. var node = queue.pop();
  10518. for (var i = node.children.length - 1; i >= 0; i--) {
  10519. if(!node.children[i].data.length){
  10520. node.children.splice(i, 1);
  10521. }
  10522. }
  10523. Array.prototype.push.apply(queue, node.children);
  10524. }
  10525. };
  10526. },{"../collision/AABB":15,"../math/Vec3":43}],64:[function(require,module,exports){
  10527. module.exports = Pool;
  10528. /**
  10529. * For pooling objects that can be reused.
  10530. * @class Pool
  10531. * @constructor
  10532. */
  10533. function Pool(){
  10534. /**
  10535. * The pooled objects
  10536. * @property {Array} objects
  10537. */
  10538. this.objects = [];
  10539. /**
  10540. * Constructor of the objects
  10541. * @property {mixed} type
  10542. */
  10543. this.type = Object;
  10544. }
  10545. /**
  10546. * Release an object after use
  10547. * @method release
  10548. * @param {Object} obj
  10549. */
  10550. Pool.prototype.release = function(){
  10551. var Nargs = arguments.length;
  10552. for(var i=0; i!==Nargs; i++){
  10553. this.objects.push(arguments[i]);
  10554. }
  10555. return this;
  10556. };
  10557. /**
  10558. * Get an object
  10559. * @method get
  10560. * @return {mixed}
  10561. */
  10562. Pool.prototype.get = function(){
  10563. if(this.objects.length===0){
  10564. return this.constructObject();
  10565. } else {
  10566. return this.objects.pop();
  10567. }
  10568. };
  10569. /**
  10570. * Construct an object. Should be implmented in each subclass.
  10571. * @method constructObject
  10572. * @return {mixed}
  10573. */
  10574. Pool.prototype.constructObject = function(){
  10575. throw new Error("constructObject() not implemented in this Pool subclass yet!");
  10576. };
  10577. /**
  10578. * @method resize
  10579. * @param {number} size
  10580. * @return {Pool} Self, for chaining
  10581. */
  10582. Pool.prototype.resize = function (size) {
  10583. var objects = this.objects;
  10584. while (objects.length > size) {
  10585. objects.pop();
  10586. }
  10587. while (objects.length < size) {
  10588. objects.push(this.constructObject());
  10589. }
  10590. return this;
  10591. };
  10592. },{}],65:[function(require,module,exports){
  10593. module.exports = TupleDictionary;
  10594. /**
  10595. * @class TupleDictionary
  10596. * @constructor
  10597. */
  10598. function TupleDictionary() {
  10599. /**
  10600. * The data storage
  10601. * @property data
  10602. * @type {Object}
  10603. */
  10604. this.data = { keys:[] };
  10605. }
  10606. /**
  10607. * @method get
  10608. * @param {Number} i
  10609. * @param {Number} j
  10610. * @return {Number}
  10611. */
  10612. TupleDictionary.prototype.get = function(i, j) {
  10613. if (i > j) {
  10614. // swap
  10615. var temp = j;
  10616. j = i;
  10617. i = temp;
  10618. }
  10619. return this.data[i+'-'+j];
  10620. };
  10621. /**
  10622. * @method set
  10623. * @param {Number} i
  10624. * @param {Number} j
  10625. * @param {Number} value
  10626. */
  10627. TupleDictionary.prototype.set = function(i, j, value) {
  10628. if (i > j) {
  10629. var temp = j;
  10630. j = i;
  10631. i = temp;
  10632. }
  10633. var key = i+'-'+j;
  10634. // Check if key already exists
  10635. if(!this.get(i,j)){
  10636. this.data.keys.push(key);
  10637. }
  10638. this.data[key] = value;
  10639. };
  10640. /**
  10641. * @method reset
  10642. */
  10643. TupleDictionary.prototype.reset = function() {
  10644. var data = this.data,
  10645. keys = data.keys;
  10646. while(keys.length > 0){
  10647. var key = keys.pop();
  10648. delete data[key];
  10649. }
  10650. };
  10651. },{}],66:[function(require,module,exports){
  10652. function Utils(){}
  10653. module.exports = Utils;
  10654. /**
  10655. * Extend an options object with default values.
  10656. * @static
  10657. * @method defaults
  10658. * @param {object} options The options object. May be falsy: in this case, a new object is created and returned.
  10659. * @param {object} defaults An object containing default values.
  10660. * @return {object} The modified options object.
  10661. */
  10662. Utils.defaults = function(options, defaults){
  10663. options = options || {};
  10664. for(var key in defaults){
  10665. if(!(key in options)){
  10666. options[key] = defaults[key];
  10667. }
  10668. }
  10669. return options;
  10670. };
  10671. },{}],67:[function(require,module,exports){
  10672. module.exports = Vec3Pool;
  10673. var Vec3 = require('../math/Vec3');
  10674. var Pool = require('./Pool');
  10675. /**
  10676. * @class Vec3Pool
  10677. * @constructor
  10678. * @extends Pool
  10679. */
  10680. function Vec3Pool(){
  10681. Pool.call(this);
  10682. this.type = Vec3;
  10683. }
  10684. Vec3Pool.prototype = new Pool();
  10685. /**
  10686. * Construct a vector
  10687. * @method constructObject
  10688. * @return {Vec3}
  10689. */
  10690. Vec3Pool.prototype.constructObject = function(){
  10691. return new Vec3();
  10692. };
  10693. },{"../math/Vec3":43,"./Pool":64}],68:[function(require,module,exports){
  10694. module.exports = Narrowphase;
  10695. var AABB = require('../collision/AABB');
  10696. var Body = require('../objects/Body');
  10697. var Shape = require('../shapes/Shape');
  10698. var Ray = require('../collision/Ray');
  10699. var Vec3 = require('../math/Vec3');
  10700. var Transform = require('../math/Transform');
  10701. var ConvexPolyhedron = require('../shapes/ConvexPolyhedron');
  10702. var Quaternion = require('../math/Quaternion');
  10703. var Solver = require('../solver/Solver');
  10704. var Vec3Pool = require('../utils/Vec3Pool');
  10705. var ContactEquation = require('../equations/ContactEquation');
  10706. var FrictionEquation = require('../equations/FrictionEquation');
  10707. /**
  10708. * Helper class for the World. Generates ContactEquations.
  10709. * @class Narrowphase
  10710. * @constructor
  10711. * @todo Sphere-ConvexPolyhedron contacts
  10712. * @todo Contact reduction
  10713. * @todo should move methods to prototype
  10714. */
  10715. function Narrowphase(world){
  10716. /**
  10717. * Internal storage of pooled contact points.
  10718. * @property {Array} contactPointPool
  10719. */
  10720. this.contactPointPool = [];
  10721. this.frictionEquationPool = [];
  10722. this.result = [];
  10723. this.frictionResult = [];
  10724. /**
  10725. * Pooled vectors.
  10726. * @property {Vec3Pool} v3pool
  10727. */
  10728. this.v3pool = new Vec3Pool();
  10729. this.world = world;
  10730. this.currentContactMaterial = null;
  10731. /**
  10732. * @property {Boolean} enableFrictionReduction
  10733. */
  10734. this.enableFrictionReduction = false;
  10735. }
  10736. /**
  10737. * Make a contact object, by using the internal pool or creating a new one.
  10738. * @method createContactEquation
  10739. * @param {Body} bi
  10740. * @param {Body} bj
  10741. * @param {Shape} si
  10742. * @param {Shape} sj
  10743. * @param {Shape} overrideShapeA
  10744. * @param {Shape} overrideShapeB
  10745. * @return {ContactEquation}
  10746. */
  10747. Narrowphase.prototype.createContactEquation = function(bi, bj, si, sj, overrideShapeA, overrideShapeB){
  10748. var c;
  10749. if(this.contactPointPool.length){
  10750. c = this.contactPointPool.pop();
  10751. c.bi = bi;
  10752. c.bj = bj;
  10753. } else {
  10754. c = new ContactEquation(bi, bj);
  10755. }
  10756. c.enabled = bi.collisionResponse && bj.collisionResponse && si.collisionResponse && sj.collisionResponse;
  10757. var cm = this.currentContactMaterial;
  10758. c.restitution = cm.restitution;
  10759. c.setSpookParams(
  10760. cm.contactEquationStiffness,
  10761. cm.contactEquationRelaxation,
  10762. this.world.dt
  10763. );
  10764. var matA = si.material || bi.material;
  10765. var matB = sj.material || bj.material;
  10766. if(matA && matB && matA.restitution >= 0 && matB.restitution >= 0){
  10767. c.restitution = matA.restitution * matB.restitution;
  10768. }
  10769. c.si = overrideShapeA || si;
  10770. c.sj = overrideShapeB || sj;
  10771. return c;
  10772. };
  10773. Narrowphase.prototype.createFrictionEquationsFromContact = function(contactEquation, outArray){
  10774. var bodyA = contactEquation.bi;
  10775. var bodyB = contactEquation.bj;
  10776. var shapeA = contactEquation.si;
  10777. var shapeB = contactEquation.sj;
  10778. var world = this.world;
  10779. var cm = this.currentContactMaterial;
  10780. // If friction or restitution were specified in the material, use them
  10781. var friction = cm.friction;
  10782. var matA = shapeA.material || bodyA.material;
  10783. var matB = shapeB.material || bodyB.material;
  10784. if(matA && matB && matA.friction >= 0 && matB.friction >= 0){
  10785. friction = matA.friction * matB.friction;
  10786. }
  10787. if(friction > 0){
  10788. // Create 2 tangent equations
  10789. var mug = friction * world.gravity.length();
  10790. var reducedMass = (bodyA.invMass + bodyB.invMass);
  10791. if(reducedMass > 0){
  10792. reducedMass = 1/reducedMass;
  10793. }
  10794. var pool = this.frictionEquationPool;
  10795. var c1 = pool.length ? pool.pop() : new FrictionEquation(bodyA,bodyB,mug*reducedMass);
  10796. var c2 = pool.length ? pool.pop() : new FrictionEquation(bodyA,bodyB,mug*reducedMass);
  10797. c1.bi = c2.bi = bodyA;
  10798. c1.bj = c2.bj = bodyB;
  10799. c1.minForce = c2.minForce = -mug*reducedMass;
  10800. c1.maxForce = c2.maxForce = mug*reducedMass;
  10801. // Copy over the relative vectors
  10802. c1.ri.copy(contactEquation.ri);
  10803. c1.rj.copy(contactEquation.rj);
  10804. c2.ri.copy(contactEquation.ri);
  10805. c2.rj.copy(contactEquation.rj);
  10806. // Construct tangents
  10807. contactEquation.ni.tangents(c1.t, c2.t);
  10808. // Set spook params
  10809. c1.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, world.dt);
  10810. c2.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, world.dt);
  10811. c1.enabled = c2.enabled = contactEquation.enabled;
  10812. outArray.push(c1, c2);
  10813. return true;
  10814. }
  10815. return false;
  10816. };
  10817. var averageNormal = new Vec3();
  10818. var averageContactPointA = new Vec3();
  10819. var averageContactPointB = new Vec3();
  10820. // Take the average N latest contact point on the plane.
  10821. Narrowphase.prototype.createFrictionFromAverage = function(numContacts){
  10822. // The last contactEquation
  10823. var c = this.result[this.result.length - 1];
  10824. // Create the result: two "average" friction equations
  10825. if (!this.createFrictionEquationsFromContact(c, this.frictionResult) || numContacts === 1) {
  10826. return;
  10827. }
  10828. var f1 = this.frictionResult[this.frictionResult.length - 2];
  10829. var f2 = this.frictionResult[this.frictionResult.length - 1];
  10830. averageNormal.setZero();
  10831. averageContactPointA.setZero();
  10832. averageContactPointB.setZero();
  10833. var bodyA = c.bi;
  10834. var bodyB = c.bj;
  10835. for(var i=0; i!==numContacts; i++){
  10836. c = this.result[this.result.length - 1 - i];
  10837. if(c.bodyA !== bodyA){
  10838. averageNormal.vadd(c.ni, averageNormal);
  10839. averageContactPointA.vadd(c.ri, averageContactPointA);
  10840. averageContactPointB.vadd(c.rj, averageContactPointB);
  10841. } else {
  10842. averageNormal.vsub(c.ni, averageNormal);
  10843. averageContactPointA.vadd(c.rj, averageContactPointA);
  10844. averageContactPointB.vadd(c.ri, averageContactPointB);
  10845. }
  10846. }
  10847. var invNumContacts = 1 / numContacts;
  10848. averageContactPointA.scale(invNumContacts, f1.ri);
  10849. averageContactPointB.scale(invNumContacts, f1.rj);
  10850. f2.ri.copy(f1.ri); // Should be the same
  10851. f2.rj.copy(f1.rj);
  10852. averageNormal.normalize();
  10853. averageNormal.tangents(f1.t, f2.t);
  10854. // return eq;
  10855. };
  10856. var tmpVec1 = new Vec3();
  10857. var tmpVec2 = new Vec3();
  10858. var tmpQuat1 = new Quaternion();
  10859. var tmpQuat2 = new Quaternion();
  10860. /**
  10861. * Generate all contacts between a list of body pairs
  10862. * @method getContacts
  10863. * @param {array} p1 Array of body indices
  10864. * @param {array} p2 Array of body indices
  10865. * @param {World} world
  10866. * @param {array} result Array to store generated contacts
  10867. * @param {array} oldcontacts Optional. Array of reusable contact objects
  10868. */
  10869. Narrowphase.prototype.getContacts = function(p1, p2, world, result, oldcontacts, frictionResult, frictionPool){
  10870. // Save old contact objects
  10871. this.contactPointPool = oldcontacts;
  10872. this.frictionEquationPool = frictionPool;
  10873. this.result = result;
  10874. this.frictionResult = frictionResult;
  10875. var qi = tmpQuat1;
  10876. var qj = tmpQuat2;
  10877. var xi = tmpVec1;
  10878. var xj = tmpVec2;
  10879. for(var k=0, N=p1.length; k!==N; k++){
  10880. // Get current collision bodies
  10881. var bi = p1[k],
  10882. bj = p2[k];
  10883. // Get contact material
  10884. var bodyContactMaterial = null;
  10885. if(bi.material && bj.material){
  10886. bodyContactMaterial = world.getContactMaterial(bi.material,bj.material) || null;
  10887. }
  10888. var justTest = (
  10889. (
  10890. (bi.type & Body.KINEMATIC) && (bj.type & Body.STATIC)
  10891. ) || (
  10892. (bi.type & Body.STATIC) && (bj.type & Body.KINEMATIC)
  10893. ) || (
  10894. (bi.type & Body.KINEMATIC) && (bj.type & Body.KINEMATIC)
  10895. )
  10896. );
  10897. for (var i = 0; i < bi.shapes.length; i++) {
  10898. bi.quaternion.mult(bi.shapeOrientations[i], qi);
  10899. bi.quaternion.vmult(bi.shapeOffsets[i], xi);
  10900. xi.vadd(bi.position, xi);
  10901. var si = bi.shapes[i];
  10902. for (var j = 0; j < bj.shapes.length; j++) {
  10903. // Compute world transform of shapes
  10904. bj.quaternion.mult(bj.shapeOrientations[j], qj);
  10905. bj.quaternion.vmult(bj.shapeOffsets[j], xj);
  10906. xj.vadd(bj.position, xj);
  10907. var sj = bj.shapes[j];
  10908. if(xi.distanceTo(xj) > si.boundingSphereRadius + sj.boundingSphereRadius){
  10909. continue;
  10910. }
  10911. // Get collision material
  10912. var shapeContactMaterial = null;
  10913. if(si.material && sj.material){
  10914. shapeContactMaterial = world.getContactMaterial(si.material,sj.material) || null;
  10915. }
  10916. this.currentContactMaterial = shapeContactMaterial || bodyContactMaterial || world.defaultContactMaterial;
  10917. // Get contacts
  10918. var resolver = this[si.type | sj.type];
  10919. if(resolver){
  10920. var retval = false;
  10921. if (si.type < sj.type) {
  10922. retval = resolver.call(this, si, sj, xi, xj, qi, qj, bi, bj, si, sj, justTest);
  10923. } else {
  10924. retval = resolver.call(this, sj, si, xj, xi, qj, qi, bj, bi, si, sj, justTest);
  10925. }
  10926. if(retval && justTest){
  10927. // Register overlap
  10928. world.shapeOverlapKeeper.set(si.id, sj.id);
  10929. world.bodyOverlapKeeper.set(bi.id, bj.id);
  10930. }
  10931. }
  10932. }
  10933. }
  10934. }
  10935. };
  10936. var numWarnings = 0;
  10937. var maxWarnings = 10;
  10938. function warn(msg){
  10939. if(numWarnings > maxWarnings){
  10940. return;
  10941. }
  10942. numWarnings++;
  10943. console.warn(msg);
  10944. }
  10945. Narrowphase.prototype[Shape.types.BOX | Shape.types.BOX] =
  10946. Narrowphase.prototype.boxBox = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  10947. si.convexPolyhedronRepresentation.material = si.material;
  10948. sj.convexPolyhedronRepresentation.material = sj.material;
  10949. si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
  10950. sj.convexPolyhedronRepresentation.collisionResponse = sj.collisionResponse;
  10951. return this.convexConvex(si.convexPolyhedronRepresentation,sj.convexPolyhedronRepresentation,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  10952. };
  10953. Narrowphase.prototype[Shape.types.BOX | Shape.types.CONVEXPOLYHEDRON] =
  10954. Narrowphase.prototype.boxConvex = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  10955. si.convexPolyhedronRepresentation.material = si.material;
  10956. si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
  10957. return this.convexConvex(si.convexPolyhedronRepresentation,sj,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  10958. };
  10959. Narrowphase.prototype[Shape.types.BOX | Shape.types.PARTICLE] =
  10960. Narrowphase.prototype.boxParticle = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  10961. si.convexPolyhedronRepresentation.material = si.material;
  10962. si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
  10963. return this.convexParticle(si.convexPolyhedronRepresentation,sj,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  10964. };
  10965. /**
  10966. * @method sphereSphere
  10967. * @param {Shape} si
  10968. * @param {Shape} sj
  10969. * @param {Vec3} xi
  10970. * @param {Vec3} xj
  10971. * @param {Quaternion} qi
  10972. * @param {Quaternion} qj
  10973. * @param {Body} bi
  10974. * @param {Body} bj
  10975. */
  10976. Narrowphase.prototype[Shape.types.SPHERE] =
  10977. Narrowphase.prototype.sphereSphere = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  10978. if(justTest){
  10979. return xi.distanceSquared(xj) < Math.pow(si.radius + sj.radius, 2);
  10980. }
  10981. // We will have only one contact in this case
  10982. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  10983. // Contact normal
  10984. xj.vsub(xi, r.ni);
  10985. r.ni.normalize();
  10986. // Contact point locations
  10987. r.ri.copy(r.ni);
  10988. r.rj.copy(r.ni);
  10989. r.ri.mult(si.radius, r.ri);
  10990. r.rj.mult(-sj.radius, r.rj);
  10991. r.ri.vadd(xi, r.ri);
  10992. r.ri.vsub(bi.position, r.ri);
  10993. r.rj.vadd(xj, r.rj);
  10994. r.rj.vsub(bj.position, r.rj);
  10995. this.result.push(r);
  10996. this.createFrictionEquationsFromContact(r, this.frictionResult);
  10997. };
  10998. /**
  10999. * @method planeTrimesh
  11000. * @param {Shape} si
  11001. * @param {Shape} sj
  11002. * @param {Vec3} xi
  11003. * @param {Vec3} xj
  11004. * @param {Quaternion} qi
  11005. * @param {Quaternion} qj
  11006. * @param {Body} bi
  11007. * @param {Body} bj
  11008. */
  11009. var planeTrimesh_normal = new Vec3();
  11010. var planeTrimesh_relpos = new Vec3();
  11011. var planeTrimesh_projected = new Vec3();
  11012. Narrowphase.prototype[Shape.types.PLANE | Shape.types.TRIMESH] =
  11013. Narrowphase.prototype.planeTrimesh = function(
  11014. planeShape,
  11015. trimeshShape,
  11016. planePos,
  11017. trimeshPos,
  11018. planeQuat,
  11019. trimeshQuat,
  11020. planeBody,
  11021. trimeshBody,
  11022. rsi,
  11023. rsj,
  11024. justTest
  11025. ){
  11026. // Make contacts!
  11027. var v = new Vec3();
  11028. var normal = planeTrimesh_normal;
  11029. normal.set(0,0,1);
  11030. planeQuat.vmult(normal,normal); // Turn normal according to plane
  11031. for(var i=0; i<trimeshShape.vertices.length / 3; i++){
  11032. // Get world vertex from trimesh
  11033. trimeshShape.getVertex(i, v);
  11034. // Safe up
  11035. var v2 = new Vec3();
  11036. v2.copy(v);
  11037. Transform.pointToWorldFrame(trimeshPos, trimeshQuat, v2, v);
  11038. // Check plane side
  11039. var relpos = planeTrimesh_relpos;
  11040. v.vsub(planePos, relpos);
  11041. var dot = normal.dot(relpos);
  11042. if(dot <= 0.0){
  11043. if(justTest){
  11044. return true;
  11045. }
  11046. var r = this.createContactEquation(planeBody,trimeshBody,planeShape,trimeshShape,rsi,rsj);
  11047. r.ni.copy(normal); // Contact normal is the plane normal
  11048. // Get vertex position projected on plane
  11049. var projected = planeTrimesh_projected;
  11050. normal.scale(relpos.dot(normal), projected);
  11051. v.vsub(projected,projected);
  11052. // ri is the projected world position minus plane position
  11053. r.ri.copy(projected);
  11054. r.ri.vsub(planeBody.position, r.ri);
  11055. r.rj.copy(v);
  11056. r.rj.vsub(trimeshBody.position, r.rj);
  11057. // Store result
  11058. this.result.push(r);
  11059. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11060. }
  11061. }
  11062. };
  11063. /**
  11064. * @method sphereTrimesh
  11065. * @param {Shape} sphereShape
  11066. * @param {Shape} trimeshShape
  11067. * @param {Vec3} spherePos
  11068. * @param {Vec3} trimeshPos
  11069. * @param {Quaternion} sphereQuat
  11070. * @param {Quaternion} trimeshQuat
  11071. * @param {Body} sphereBody
  11072. * @param {Body} trimeshBody
  11073. */
  11074. var sphereTrimesh_normal = new Vec3();
  11075. var sphereTrimesh_relpos = new Vec3();
  11076. var sphereTrimesh_projected = new Vec3();
  11077. var sphereTrimesh_v = new Vec3();
  11078. var sphereTrimesh_v2 = new Vec3();
  11079. var sphereTrimesh_edgeVertexA = new Vec3();
  11080. var sphereTrimesh_edgeVertexB = new Vec3();
  11081. var sphereTrimesh_edgeVector = new Vec3();
  11082. var sphereTrimesh_edgeVectorUnit = new Vec3();
  11083. var sphereTrimesh_localSpherePos = new Vec3();
  11084. var sphereTrimesh_tmp = new Vec3();
  11085. var sphereTrimesh_va = new Vec3();
  11086. var sphereTrimesh_vb = new Vec3();
  11087. var sphereTrimesh_vc = new Vec3();
  11088. var sphereTrimesh_localSphereAABB = new AABB();
  11089. var sphereTrimesh_triangles = [];
  11090. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.TRIMESH] =
  11091. Narrowphase.prototype.sphereTrimesh = function (
  11092. sphereShape,
  11093. trimeshShape,
  11094. spherePos,
  11095. trimeshPos,
  11096. sphereQuat,
  11097. trimeshQuat,
  11098. sphereBody,
  11099. trimeshBody,
  11100. rsi,
  11101. rsj,
  11102. justTest
  11103. ) {
  11104. var edgeVertexA = sphereTrimesh_edgeVertexA;
  11105. var edgeVertexB = sphereTrimesh_edgeVertexB;
  11106. var edgeVector = sphereTrimesh_edgeVector;
  11107. var edgeVectorUnit = sphereTrimesh_edgeVectorUnit;
  11108. var localSpherePos = sphereTrimesh_localSpherePos;
  11109. var tmp = sphereTrimesh_tmp;
  11110. var localSphereAABB = sphereTrimesh_localSphereAABB;
  11111. var v2 = sphereTrimesh_v2;
  11112. var relpos = sphereTrimesh_relpos;
  11113. var triangles = sphereTrimesh_triangles;
  11114. // Convert sphere position to local in the trimesh
  11115. Transform.pointToLocalFrame(trimeshPos, trimeshQuat, spherePos, localSpherePos);
  11116. // Get the aabb of the sphere locally in the trimesh
  11117. var sphereRadius = sphereShape.radius;
  11118. localSphereAABB.lowerBound.set(
  11119. localSpherePos.x - sphereRadius,
  11120. localSpherePos.y - sphereRadius,
  11121. localSpherePos.z - sphereRadius
  11122. );
  11123. localSphereAABB.upperBound.set(
  11124. localSpherePos.x + sphereRadius,
  11125. localSpherePos.y + sphereRadius,
  11126. localSpherePos.z + sphereRadius
  11127. );
  11128. trimeshShape.getTrianglesInAABB(localSphereAABB, triangles);
  11129. //for (var i = 0; i < trimeshShape.indices.length / 3; i++) triangles.push(i); // All
  11130. // Vertices
  11131. var v = sphereTrimesh_v;
  11132. var radiusSquared = sphereShape.radius * sphereShape.radius;
  11133. for(var i=0; i<triangles.length; i++){
  11134. for (var j = 0; j < 3; j++) {
  11135. trimeshShape.getVertex(trimeshShape.indices[triangles[i] * 3 + j], v);
  11136. // Check vertex overlap in sphere
  11137. v.vsub(localSpherePos, relpos);
  11138. if(relpos.norm2() <= radiusSquared){
  11139. // Safe up
  11140. v2.copy(v);
  11141. Transform.pointToWorldFrame(trimeshPos, trimeshQuat, v2, v);
  11142. v.vsub(spherePos, relpos);
  11143. if(justTest){
  11144. return true;
  11145. }
  11146. var r = this.createContactEquation(sphereBody,trimeshBody,sphereShape,trimeshShape,rsi,rsj);
  11147. r.ni.copy(relpos);
  11148. r.ni.normalize();
  11149. // ri is the vector from sphere center to the sphere surface
  11150. r.ri.copy(r.ni);
  11151. r.ri.scale(sphereShape.radius, r.ri);
  11152. r.ri.vadd(spherePos, r.ri);
  11153. r.ri.vsub(sphereBody.position, r.ri);
  11154. r.rj.copy(v);
  11155. r.rj.vsub(trimeshBody.position, r.rj);
  11156. // Store result
  11157. this.result.push(r);
  11158. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11159. }
  11160. }
  11161. }
  11162. // Check all edges
  11163. for(var i=0; i<triangles.length; i++){
  11164. for (var j = 0; j < 3; j++) {
  11165. trimeshShape.getVertex(trimeshShape.indices[triangles[i] * 3 + j], edgeVertexA);
  11166. trimeshShape.getVertex(trimeshShape.indices[triangles[i] * 3 + ((j+1)%3)], edgeVertexB);
  11167. edgeVertexB.vsub(edgeVertexA, edgeVector);
  11168. // Project sphere position to the edge
  11169. localSpherePos.vsub(edgeVertexB, tmp);
  11170. var positionAlongEdgeB = tmp.dot(edgeVector);
  11171. localSpherePos.vsub(edgeVertexA, tmp);
  11172. var positionAlongEdgeA = tmp.dot(edgeVector);
  11173. if(positionAlongEdgeA > 0 && positionAlongEdgeB < 0){
  11174. // Now check the orthogonal distance from edge to sphere center
  11175. localSpherePos.vsub(edgeVertexA, tmp);
  11176. edgeVectorUnit.copy(edgeVector);
  11177. edgeVectorUnit.normalize();
  11178. positionAlongEdgeA = tmp.dot(edgeVectorUnit);
  11179. edgeVectorUnit.scale(positionAlongEdgeA, tmp);
  11180. tmp.vadd(edgeVertexA, tmp);
  11181. // tmp is now the sphere center position projected to the edge, defined locally in the trimesh frame
  11182. var dist = tmp.distanceTo(localSpherePos);
  11183. if(dist < sphereShape.radius){
  11184. if(justTest){
  11185. return true;
  11186. }
  11187. var r = this.createContactEquation(sphereBody, trimeshBody, sphereShape, trimeshShape,rsi,rsj);
  11188. tmp.vsub(localSpherePos, r.ni);
  11189. r.ni.normalize();
  11190. r.ni.scale(sphereShape.radius, r.ri);
  11191. Transform.pointToWorldFrame(trimeshPos, trimeshQuat, tmp, tmp);
  11192. tmp.vsub(trimeshBody.position, r.rj);
  11193. Transform.vectorToWorldFrame(trimeshQuat, r.ni, r.ni);
  11194. Transform.vectorToWorldFrame(trimeshQuat, r.ri, r.ri);
  11195. this.result.push(r);
  11196. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11197. }
  11198. }
  11199. }
  11200. }
  11201. // Triangle faces
  11202. var va = sphereTrimesh_va;
  11203. var vb = sphereTrimesh_vb;
  11204. var vc = sphereTrimesh_vc;
  11205. var normal = sphereTrimesh_normal;
  11206. for(var i=0, N = triangles.length; i !== N; i++){
  11207. trimeshShape.getTriangleVertices(triangles[i], va, vb, vc);
  11208. trimeshShape.getNormal(triangles[i], normal);
  11209. localSpherePos.vsub(va, tmp);
  11210. var dist = tmp.dot(normal);
  11211. normal.scale(dist, tmp);
  11212. localSpherePos.vsub(tmp, tmp);
  11213. // tmp is now the sphere position projected to the triangle plane
  11214. dist = tmp.distanceTo(localSpherePos);
  11215. if(Ray.pointInTriangle(tmp, va, vb, vc) && dist < sphereShape.radius){
  11216. if(justTest){
  11217. return true;
  11218. }
  11219. var r = this.createContactEquation(sphereBody, trimeshBody, sphereShape, trimeshShape,rsi,rsj);
  11220. tmp.vsub(localSpherePos, r.ni);
  11221. r.ni.normalize();
  11222. r.ni.scale(sphereShape.radius, r.ri);
  11223. Transform.pointToWorldFrame(trimeshPos, trimeshQuat, tmp, tmp);
  11224. tmp.vsub(trimeshBody.position, r.rj);
  11225. Transform.vectorToWorldFrame(trimeshQuat, r.ni, r.ni);
  11226. Transform.vectorToWorldFrame(trimeshQuat, r.ri, r.ri);
  11227. this.result.push(r);
  11228. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11229. }
  11230. }
  11231. triangles.length = 0;
  11232. };
  11233. var point_on_plane_to_sphere = new Vec3();
  11234. var plane_to_sphere_ortho = new Vec3();
  11235. /**
  11236. * @method spherePlane
  11237. * @param {Shape} si
  11238. * @param {Shape} sj
  11239. * @param {Vec3} xi
  11240. * @param {Vec3} xj
  11241. * @param {Quaternion} qi
  11242. * @param {Quaternion} qj
  11243. * @param {Body} bi
  11244. * @param {Body} bj
  11245. */
  11246. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.PLANE] =
  11247. Narrowphase.prototype.spherePlane = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  11248. // We will have one contact in this case
  11249. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  11250. // Contact normal
  11251. r.ni.set(0,0,1);
  11252. qj.vmult(r.ni, r.ni);
  11253. r.ni.negate(r.ni); // body i is the sphere, flip normal
  11254. r.ni.normalize(); // Needed?
  11255. // Vector from sphere center to contact point
  11256. r.ni.mult(si.radius, r.ri);
  11257. // Project down sphere on plane
  11258. xi.vsub(xj, point_on_plane_to_sphere);
  11259. r.ni.mult(r.ni.dot(point_on_plane_to_sphere), plane_to_sphere_ortho);
  11260. point_on_plane_to_sphere.vsub(plane_to_sphere_ortho,r.rj); // The sphere position projected to plane
  11261. if(-point_on_plane_to_sphere.dot(r.ni) <= si.radius){
  11262. if(justTest){
  11263. return true;
  11264. }
  11265. // Make it relative to the body
  11266. var ri = r.ri;
  11267. var rj = r.rj;
  11268. ri.vadd(xi, ri);
  11269. ri.vsub(bi.position, ri);
  11270. rj.vadd(xj, rj);
  11271. rj.vsub(bj.position, rj);
  11272. this.result.push(r);
  11273. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11274. }
  11275. };
  11276. // See http://bulletphysics.com/Bullet/BulletFull/SphereTriangleDetector_8cpp_source.html
  11277. var pointInPolygon_edge = new Vec3();
  11278. var pointInPolygon_edge_x_normal = new Vec3();
  11279. var pointInPolygon_vtp = new Vec3();
  11280. function pointInPolygon(verts, normal, p){
  11281. var positiveResult = null;
  11282. var N = verts.length;
  11283. for(var i=0; i!==N; i++){
  11284. var v = verts[i];
  11285. // Get edge to the next vertex
  11286. var edge = pointInPolygon_edge;
  11287. verts[(i+1) % (N)].vsub(v,edge);
  11288. // Get cross product between polygon normal and the edge
  11289. var edge_x_normal = pointInPolygon_edge_x_normal;
  11290. //var edge_x_normal = new Vec3();
  11291. edge.cross(normal,edge_x_normal);
  11292. // Get vector between point and current vertex
  11293. var vertex_to_p = pointInPolygon_vtp;
  11294. p.vsub(v,vertex_to_p);
  11295. // This dot product determines which side of the edge the point is
  11296. var r = edge_x_normal.dot(vertex_to_p);
  11297. // If all such dot products have same sign, we are inside the polygon.
  11298. if(positiveResult===null || (r>0 && positiveResult===true) || (r<=0 && positiveResult===false)){
  11299. if(positiveResult===null){
  11300. positiveResult = r>0;
  11301. }
  11302. continue;
  11303. } else {
  11304. return false; // Encountered some other sign. Exit.
  11305. }
  11306. }
  11307. // If we got here, all dot products were of the same sign.
  11308. return true;
  11309. }
  11310. var box_to_sphere = new Vec3();
  11311. var sphereBox_ns = new Vec3();
  11312. var sphereBox_ns1 = new Vec3();
  11313. var sphereBox_ns2 = new Vec3();
  11314. var sphereBox_sides = [new Vec3(),new Vec3(),new Vec3(),new Vec3(),new Vec3(),new Vec3()];
  11315. var sphereBox_sphere_to_corner = new Vec3();
  11316. var sphereBox_side_ns = new Vec3();
  11317. var sphereBox_side_ns1 = new Vec3();
  11318. var sphereBox_side_ns2 = new Vec3();
  11319. /**
  11320. * @method sphereBox
  11321. * @param {Shape} si
  11322. * @param {Shape} sj
  11323. * @param {Vec3} xi
  11324. * @param {Vec3} xj
  11325. * @param {Quaternion} qi
  11326. * @param {Quaternion} qj
  11327. * @param {Body} bi
  11328. * @param {Body} bj
  11329. */
  11330. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.BOX] =
  11331. Narrowphase.prototype.sphereBox = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  11332. var v3pool = this.v3pool;
  11333. // we refer to the box as body j
  11334. var sides = sphereBox_sides;
  11335. xi.vsub(xj,box_to_sphere);
  11336. sj.getSideNormals(sides,qj);
  11337. var R = si.radius;
  11338. var penetrating_sides = [];
  11339. // Check side (plane) intersections
  11340. var found = false;
  11341. // Store the resulting side penetration info
  11342. var side_ns = sphereBox_side_ns;
  11343. var side_ns1 = sphereBox_side_ns1;
  11344. var side_ns2 = sphereBox_side_ns2;
  11345. var side_h = null;
  11346. var side_penetrations = 0;
  11347. var side_dot1 = 0;
  11348. var side_dot2 = 0;
  11349. var side_distance = null;
  11350. for(var idx=0,nsides=sides.length; idx!==nsides && found===false; idx++){
  11351. // Get the plane side normal (ns)
  11352. var ns = sphereBox_ns;
  11353. ns.copy(sides[idx]);
  11354. var h = ns.norm();
  11355. ns.normalize();
  11356. // The normal/distance dot product tells which side of the plane we are
  11357. var dot = box_to_sphere.dot(ns);
  11358. if(dot<h+R && dot>0){
  11359. // Intersects plane. Now check the other two dimensions
  11360. var ns1 = sphereBox_ns1;
  11361. var ns2 = sphereBox_ns2;
  11362. ns1.copy(sides[(idx+1)%3]);
  11363. ns2.copy(sides[(idx+2)%3]);
  11364. var h1 = ns1.norm();
  11365. var h2 = ns2.norm();
  11366. ns1.normalize();
  11367. ns2.normalize();
  11368. var dot1 = box_to_sphere.dot(ns1);
  11369. var dot2 = box_to_sphere.dot(ns2);
  11370. if(dot1<h1 && dot1>-h1 && dot2<h2 && dot2>-h2){
  11371. var dist = Math.abs(dot-h-R);
  11372. if(side_distance===null || dist < side_distance){
  11373. side_distance = dist;
  11374. side_dot1 = dot1;
  11375. side_dot2 = dot2;
  11376. side_h = h;
  11377. side_ns.copy(ns);
  11378. side_ns1.copy(ns1);
  11379. side_ns2.copy(ns2);
  11380. side_penetrations++;
  11381. if(justTest){
  11382. return true;
  11383. }
  11384. }
  11385. }
  11386. }
  11387. }
  11388. if(side_penetrations){
  11389. found = true;
  11390. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  11391. side_ns.mult(-R,r.ri); // Sphere r
  11392. r.ni.copy(side_ns);
  11393. r.ni.negate(r.ni); // Normal should be out of sphere
  11394. side_ns.mult(side_h,side_ns);
  11395. side_ns1.mult(side_dot1,side_ns1);
  11396. side_ns.vadd(side_ns1,side_ns);
  11397. side_ns2.mult(side_dot2,side_ns2);
  11398. side_ns.vadd(side_ns2,r.rj);
  11399. // Make relative to bodies
  11400. r.ri.vadd(xi, r.ri);
  11401. r.ri.vsub(bi.position, r.ri);
  11402. r.rj.vadd(xj, r.rj);
  11403. r.rj.vsub(bj.position, r.rj);
  11404. this.result.push(r);
  11405. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11406. }
  11407. // Check corners
  11408. var rj = v3pool.get();
  11409. var sphere_to_corner = sphereBox_sphere_to_corner;
  11410. for(var j=0; j!==2 && !found; j++){
  11411. for(var k=0; k!==2 && !found; k++){
  11412. for(var l=0; l!==2 && !found; l++){
  11413. rj.set(0,0,0);
  11414. if(j){
  11415. rj.vadd(sides[0],rj);
  11416. } else {
  11417. rj.vsub(sides[0],rj);
  11418. }
  11419. if(k){
  11420. rj.vadd(sides[1],rj);
  11421. } else {
  11422. rj.vsub(sides[1],rj);
  11423. }
  11424. if(l){
  11425. rj.vadd(sides[2],rj);
  11426. } else {
  11427. rj.vsub(sides[2],rj);
  11428. }
  11429. // World position of corner
  11430. xj.vadd(rj,sphere_to_corner);
  11431. sphere_to_corner.vsub(xi,sphere_to_corner);
  11432. if(sphere_to_corner.norm2() < R*R){
  11433. if(justTest){
  11434. return true;
  11435. }
  11436. found = true;
  11437. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  11438. r.ri.copy(sphere_to_corner);
  11439. r.ri.normalize();
  11440. r.ni.copy(r.ri);
  11441. r.ri.mult(R,r.ri);
  11442. r.rj.copy(rj);
  11443. // Make relative to bodies
  11444. r.ri.vadd(xi, r.ri);
  11445. r.ri.vsub(bi.position, r.ri);
  11446. r.rj.vadd(xj, r.rj);
  11447. r.rj.vsub(bj.position, r.rj);
  11448. this.result.push(r);
  11449. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11450. }
  11451. }
  11452. }
  11453. }
  11454. v3pool.release(rj);
  11455. rj = null;
  11456. // Check edges
  11457. var edgeTangent = v3pool.get();
  11458. var edgeCenter = v3pool.get();
  11459. var r = v3pool.get(); // r = edge center to sphere center
  11460. var orthogonal = v3pool.get();
  11461. var dist = v3pool.get();
  11462. var Nsides = sides.length;
  11463. for(var j=0; j!==Nsides && !found; j++){
  11464. for(var k=0; k!==Nsides && !found; k++){
  11465. if(j%3 !== k%3){
  11466. // Get edge tangent
  11467. sides[k].cross(sides[j],edgeTangent);
  11468. edgeTangent.normalize();
  11469. sides[j].vadd(sides[k], edgeCenter);
  11470. r.copy(xi);
  11471. r.vsub(edgeCenter,r);
  11472. r.vsub(xj,r);
  11473. var orthonorm = r.dot(edgeTangent); // distance from edge center to sphere center in the tangent direction
  11474. edgeTangent.mult(orthonorm,orthogonal); // Vector from edge center to sphere center in the tangent direction
  11475. // Find the third side orthogonal to this one
  11476. var l = 0;
  11477. while(l===j%3 || l===k%3){
  11478. l++;
  11479. }
  11480. // vec from edge center to sphere projected to the plane orthogonal to the edge tangent
  11481. dist.copy(xi);
  11482. dist.vsub(orthogonal,dist);
  11483. dist.vsub(edgeCenter,dist);
  11484. dist.vsub(xj,dist);
  11485. // Distances in tangent direction and distance in the plane orthogonal to it
  11486. var tdist = Math.abs(orthonorm);
  11487. var ndist = dist.norm();
  11488. if(tdist < sides[l].norm() && ndist<R){
  11489. if(justTest){
  11490. return true;
  11491. }
  11492. found = true;
  11493. var res = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  11494. edgeCenter.vadd(orthogonal,res.rj); // box rj
  11495. res.rj.copy(res.rj);
  11496. dist.negate(res.ni);
  11497. res.ni.normalize();
  11498. res.ri.copy(res.rj);
  11499. res.ri.vadd(xj,res.ri);
  11500. res.ri.vsub(xi,res.ri);
  11501. res.ri.normalize();
  11502. res.ri.mult(R,res.ri);
  11503. // Make relative to bodies
  11504. res.ri.vadd(xi, res.ri);
  11505. res.ri.vsub(bi.position, res.ri);
  11506. res.rj.vadd(xj, res.rj);
  11507. res.rj.vsub(bj.position, res.rj);
  11508. this.result.push(res);
  11509. this.createFrictionEquationsFromContact(res, this.frictionResult);
  11510. }
  11511. }
  11512. }
  11513. }
  11514. v3pool.release(edgeTangent,edgeCenter,r,orthogonal,dist);
  11515. };
  11516. var convex_to_sphere = new Vec3();
  11517. var sphereConvex_edge = new Vec3();
  11518. var sphereConvex_edgeUnit = new Vec3();
  11519. var sphereConvex_sphereToCorner = new Vec3();
  11520. var sphereConvex_worldCorner = new Vec3();
  11521. var sphereConvex_worldNormal = new Vec3();
  11522. var sphereConvex_worldPoint = new Vec3();
  11523. var sphereConvex_worldSpherePointClosestToPlane = new Vec3();
  11524. var sphereConvex_penetrationVec = new Vec3();
  11525. var sphereConvex_sphereToWorldPoint = new Vec3();
  11526. /**
  11527. * @method sphereConvex
  11528. * @param {Shape} si
  11529. * @param {Shape} sj
  11530. * @param {Vec3} xi
  11531. * @param {Vec3} xj
  11532. * @param {Quaternion} qi
  11533. * @param {Quaternion} qj
  11534. * @param {Body} bi
  11535. * @param {Body} bj
  11536. */
  11537. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.CONVEXPOLYHEDRON] =
  11538. Narrowphase.prototype.sphereConvex = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  11539. var v3pool = this.v3pool;
  11540. xi.vsub(xj,convex_to_sphere);
  11541. var normals = sj.faceNormals;
  11542. var faces = sj.faces;
  11543. var verts = sj.vertices;
  11544. var R = si.radius;
  11545. var penetrating_sides = [];
  11546. // if(convex_to_sphere.norm2() > si.boundingSphereRadius + sj.boundingSphereRadius){
  11547. // return;
  11548. // }
  11549. // Check corners
  11550. for(var i=0; i!==verts.length; i++){
  11551. var v = verts[i];
  11552. // World position of corner
  11553. var worldCorner = sphereConvex_worldCorner;
  11554. qj.vmult(v,worldCorner);
  11555. xj.vadd(worldCorner,worldCorner);
  11556. var sphere_to_corner = sphereConvex_sphereToCorner;
  11557. worldCorner.vsub(xi, sphere_to_corner);
  11558. if(sphere_to_corner.norm2() < R * R){
  11559. if(justTest){
  11560. return true;
  11561. }
  11562. found = true;
  11563. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  11564. r.ri.copy(sphere_to_corner);
  11565. r.ri.normalize();
  11566. r.ni.copy(r.ri);
  11567. r.ri.mult(R,r.ri);
  11568. worldCorner.vsub(xj,r.rj);
  11569. // Should be relative to the body.
  11570. r.ri.vadd(xi, r.ri);
  11571. r.ri.vsub(bi.position, r.ri);
  11572. // Should be relative to the body.
  11573. r.rj.vadd(xj, r.rj);
  11574. r.rj.vsub(bj.position, r.rj);
  11575. this.result.push(r);
  11576. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11577. return;
  11578. }
  11579. }
  11580. // Check side (plane) intersections
  11581. var found = false;
  11582. for(var i=0, nfaces=faces.length; i!==nfaces && found===false; i++){
  11583. var normal = normals[i];
  11584. var face = faces[i];
  11585. // Get world-transformed normal of the face
  11586. var worldNormal = sphereConvex_worldNormal;
  11587. qj.vmult(normal,worldNormal);
  11588. // Get a world vertex from the face
  11589. var worldPoint = sphereConvex_worldPoint;
  11590. qj.vmult(verts[face[0]],worldPoint);
  11591. worldPoint.vadd(xj,worldPoint);
  11592. // Get a point on the sphere, closest to the face normal
  11593. var worldSpherePointClosestToPlane = sphereConvex_worldSpherePointClosestToPlane;
  11594. worldNormal.mult(-R, worldSpherePointClosestToPlane);
  11595. xi.vadd(worldSpherePointClosestToPlane, worldSpherePointClosestToPlane);
  11596. // Vector from a face point to the closest point on the sphere
  11597. var penetrationVec = sphereConvex_penetrationVec;
  11598. worldSpherePointClosestToPlane.vsub(worldPoint,penetrationVec);
  11599. // The penetration. Negative value means overlap.
  11600. var penetration = penetrationVec.dot(worldNormal);
  11601. var worldPointToSphere = sphereConvex_sphereToWorldPoint;
  11602. xi.vsub(worldPoint, worldPointToSphere);
  11603. if(penetration < 0 && worldPointToSphere.dot(worldNormal)>0){
  11604. // Intersects plane. Now check if the sphere is inside the face polygon
  11605. var faceVerts = []; // Face vertices, in world coords
  11606. for(var j=0, Nverts=face.length; j!==Nverts; j++){
  11607. var worldVertex = v3pool.get();
  11608. qj.vmult(verts[face[j]], worldVertex);
  11609. xj.vadd(worldVertex,worldVertex);
  11610. faceVerts.push(worldVertex);
  11611. }
  11612. if(pointInPolygon(faceVerts,worldNormal,xi)){ // Is the sphere center in the face polygon?
  11613. if(justTest){
  11614. return true;
  11615. }
  11616. found = true;
  11617. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  11618. worldNormal.mult(-R, r.ri); // Contact offset, from sphere center to contact
  11619. worldNormal.negate(r.ni); // Normal pointing out of sphere
  11620. var penetrationVec2 = v3pool.get();
  11621. worldNormal.mult(-penetration, penetrationVec2);
  11622. var penetrationSpherePoint = v3pool.get();
  11623. worldNormal.mult(-R, penetrationSpherePoint);
  11624. //xi.vsub(xj).vadd(penetrationSpherePoint).vadd(penetrationVec2 , r.rj);
  11625. xi.vsub(xj,r.rj);
  11626. r.rj.vadd(penetrationSpherePoint,r.rj);
  11627. r.rj.vadd(penetrationVec2 , r.rj);
  11628. // Should be relative to the body.
  11629. r.rj.vadd(xj, r.rj);
  11630. r.rj.vsub(bj.position, r.rj);
  11631. // Should be relative to the body.
  11632. r.ri.vadd(xi, r.ri);
  11633. r.ri.vsub(bi.position, r.ri);
  11634. v3pool.release(penetrationVec2);
  11635. v3pool.release(penetrationSpherePoint);
  11636. this.result.push(r);
  11637. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11638. // Release world vertices
  11639. for(var j=0, Nfaceverts=faceVerts.length; j!==Nfaceverts; j++){
  11640. v3pool.release(faceVerts[j]);
  11641. }
  11642. return; // We only expect *one* face contact
  11643. } else {
  11644. // Edge?
  11645. for(var j=0; j!==face.length; j++){
  11646. // Get two world transformed vertices
  11647. var v1 = v3pool.get();
  11648. var v2 = v3pool.get();
  11649. qj.vmult(verts[face[(j+1)%face.length]], v1);
  11650. qj.vmult(verts[face[(j+2)%face.length]], v2);
  11651. xj.vadd(v1, v1);
  11652. xj.vadd(v2, v2);
  11653. // Construct edge vector
  11654. var edge = sphereConvex_edge;
  11655. v2.vsub(v1,edge);
  11656. // Construct the same vector, but normalized
  11657. var edgeUnit = sphereConvex_edgeUnit;
  11658. edge.unit(edgeUnit);
  11659. // p is xi projected onto the edge
  11660. var p = v3pool.get();
  11661. var v1_to_xi = v3pool.get();
  11662. xi.vsub(v1, v1_to_xi);
  11663. var dot = v1_to_xi.dot(edgeUnit);
  11664. edgeUnit.mult(dot, p);
  11665. p.vadd(v1, p);
  11666. // Compute a vector from p to the center of the sphere
  11667. var xi_to_p = v3pool.get();
  11668. p.vsub(xi, xi_to_p);
  11669. // Collision if the edge-sphere distance is less than the radius
  11670. // AND if p is in between v1 and v2
  11671. if(dot > 0 && dot*dot<edge.norm2() && xi_to_p.norm2() < R*R){ // Collision if the edge-sphere distance is less than the radius
  11672. // Edge contact!
  11673. if(justTest){
  11674. return true;
  11675. }
  11676. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  11677. p.vsub(xj,r.rj);
  11678. p.vsub(xi,r.ni);
  11679. r.ni.normalize();
  11680. r.ni.mult(R,r.ri);
  11681. // Should be relative to the body.
  11682. r.rj.vadd(xj, r.rj);
  11683. r.rj.vsub(bj.position, r.rj);
  11684. // Should be relative to the body.
  11685. r.ri.vadd(xi, r.ri);
  11686. r.ri.vsub(bi.position, r.ri);
  11687. this.result.push(r);
  11688. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11689. // Release world vertices
  11690. for(var j=0, Nfaceverts=faceVerts.length; j!==Nfaceverts; j++){
  11691. v3pool.release(faceVerts[j]);
  11692. }
  11693. v3pool.release(v1);
  11694. v3pool.release(v2);
  11695. v3pool.release(p);
  11696. v3pool.release(xi_to_p);
  11697. v3pool.release(v1_to_xi);
  11698. return;
  11699. }
  11700. v3pool.release(v1);
  11701. v3pool.release(v2);
  11702. v3pool.release(p);
  11703. v3pool.release(xi_to_p);
  11704. v3pool.release(v1_to_xi);
  11705. }
  11706. }
  11707. // Release world vertices
  11708. for(var j=0, Nfaceverts=faceVerts.length; j!==Nfaceverts; j++){
  11709. v3pool.release(faceVerts[j]);
  11710. }
  11711. }
  11712. }
  11713. };
  11714. var planeBox_normal = new Vec3();
  11715. var plane_to_corner = new Vec3();
  11716. /**
  11717. * @method planeBox
  11718. * @param {Array} result
  11719. * @param {Shape} si
  11720. * @param {Shape} sj
  11721. * @param {Vec3} xi
  11722. * @param {Vec3} xj
  11723. * @param {Quaternion} qi
  11724. * @param {Quaternion} qj
  11725. * @param {Body} bi
  11726. * @param {Body} bj
  11727. */
  11728. Narrowphase.prototype[Shape.types.PLANE | Shape.types.BOX] =
  11729. Narrowphase.prototype.planeBox = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  11730. sj.convexPolyhedronRepresentation.material = sj.material;
  11731. sj.convexPolyhedronRepresentation.collisionResponse = sj.collisionResponse;
  11732. sj.convexPolyhedronRepresentation.id = sj.id;
  11733. return this.planeConvex(si,sj.convexPolyhedronRepresentation,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  11734. };
  11735. var planeConvex_v = new Vec3();
  11736. var planeConvex_normal = new Vec3();
  11737. var planeConvex_relpos = new Vec3();
  11738. var planeConvex_projected = new Vec3();
  11739. /**
  11740. * @method planeConvex
  11741. * @param {Shape} si
  11742. * @param {Shape} sj
  11743. * @param {Vec3} xi
  11744. * @param {Vec3} xj
  11745. * @param {Quaternion} qi
  11746. * @param {Quaternion} qj
  11747. * @param {Body} bi
  11748. * @param {Body} bj
  11749. */
  11750. Narrowphase.prototype[Shape.types.PLANE | Shape.types.CONVEXPOLYHEDRON] =
  11751. Narrowphase.prototype.planeConvex = function(
  11752. planeShape,
  11753. convexShape,
  11754. planePosition,
  11755. convexPosition,
  11756. planeQuat,
  11757. convexQuat,
  11758. planeBody,
  11759. convexBody,
  11760. si,
  11761. sj,
  11762. justTest
  11763. ){
  11764. // Simply return the points behind the plane.
  11765. var worldVertex = planeConvex_v,
  11766. worldNormal = planeConvex_normal;
  11767. worldNormal.set(0,0,1);
  11768. planeQuat.vmult(worldNormal,worldNormal); // Turn normal according to plane orientation
  11769. var numContacts = 0;
  11770. var relpos = planeConvex_relpos;
  11771. for(var i = 0; i !== convexShape.vertices.length; i++){
  11772. // Get world convex vertex
  11773. worldVertex.copy(convexShape.vertices[i]);
  11774. convexQuat.vmult(worldVertex, worldVertex);
  11775. convexPosition.vadd(worldVertex, worldVertex);
  11776. worldVertex.vsub(planePosition, relpos);
  11777. var dot = worldNormal.dot(relpos);
  11778. if(dot <= 0.0){
  11779. if(justTest){
  11780. return true;
  11781. }
  11782. var r = this.createContactEquation(planeBody, convexBody, planeShape, convexShape, si, sj);
  11783. // Get vertex position projected on plane
  11784. var projected = planeConvex_projected;
  11785. worldNormal.mult(worldNormal.dot(relpos),projected);
  11786. worldVertex.vsub(projected, projected);
  11787. projected.vsub(planePosition, r.ri); // From plane to vertex projected on plane
  11788. r.ni.copy(worldNormal); // Contact normal is the plane normal out from plane
  11789. // rj is now just the vector from the convex center to the vertex
  11790. worldVertex.vsub(convexPosition, r.rj);
  11791. // Make it relative to the body
  11792. r.ri.vadd(planePosition, r.ri);
  11793. r.ri.vsub(planeBody.position, r.ri);
  11794. r.rj.vadd(convexPosition, r.rj);
  11795. r.rj.vsub(convexBody.position, r.rj);
  11796. this.result.push(r);
  11797. numContacts++;
  11798. if(!this.enableFrictionReduction){
  11799. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11800. }
  11801. }
  11802. }
  11803. if(this.enableFrictionReduction && numContacts){
  11804. this.createFrictionFromAverage(numContacts);
  11805. }
  11806. };
  11807. var convexConvex_sepAxis = new Vec3();
  11808. var convexConvex_q = new Vec3();
  11809. /**
  11810. * @method convexConvex
  11811. * @param {Shape} si
  11812. * @param {Shape} sj
  11813. * @param {Vec3} xi
  11814. * @param {Vec3} xj
  11815. * @param {Quaternion} qi
  11816. * @param {Quaternion} qj
  11817. * @param {Body} bi
  11818. * @param {Body} bj
  11819. */
  11820. Narrowphase.prototype[Shape.types.CONVEXPOLYHEDRON] =
  11821. Narrowphase.prototype.convexConvex = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest,faceListA,faceListB){
  11822. var sepAxis = convexConvex_sepAxis;
  11823. if(xi.distanceTo(xj) > si.boundingSphereRadius + sj.boundingSphereRadius){
  11824. return;
  11825. }
  11826. if(si.findSeparatingAxis(sj,xi,qi,xj,qj,sepAxis,faceListA,faceListB)){
  11827. var res = [];
  11828. var q = convexConvex_q;
  11829. si.clipAgainstHull(xi,qi,sj,xj,qj,sepAxis,-100,100,res);
  11830. var numContacts = 0;
  11831. for(var j = 0; j !== res.length; j++){
  11832. if(justTest){
  11833. return true;
  11834. }
  11835. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj),
  11836. ri = r.ri,
  11837. rj = r.rj;
  11838. sepAxis.negate(r.ni);
  11839. res[j].normal.negate(q);
  11840. q.mult(res[j].depth, q);
  11841. res[j].point.vadd(q, ri);
  11842. rj.copy(res[j].point);
  11843. // Contact points are in world coordinates. Transform back to relative
  11844. ri.vsub(xi,ri);
  11845. rj.vsub(xj,rj);
  11846. // Make relative to bodies
  11847. ri.vadd(xi, ri);
  11848. ri.vsub(bi.position, ri);
  11849. rj.vadd(xj, rj);
  11850. rj.vsub(bj.position, rj);
  11851. this.result.push(r);
  11852. numContacts++;
  11853. if(!this.enableFrictionReduction){
  11854. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11855. }
  11856. }
  11857. if(this.enableFrictionReduction && numContacts){
  11858. this.createFrictionFromAverage(numContacts);
  11859. }
  11860. }
  11861. };
  11862. /**
  11863. * @method convexTrimesh
  11864. * @param {Array} result
  11865. * @param {Shape} si
  11866. * @param {Shape} sj
  11867. * @param {Vec3} xi
  11868. * @param {Vec3} xj
  11869. * @param {Quaternion} qi
  11870. * @param {Quaternion} qj
  11871. * @param {Body} bi
  11872. * @param {Body} bj
  11873. */
  11874. // Narrowphase.prototype[Shape.types.CONVEXPOLYHEDRON | Shape.types.TRIMESH] =
  11875. // Narrowphase.prototype.convexTrimesh = function(si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,faceListA,faceListB){
  11876. // var sepAxis = convexConvex_sepAxis;
  11877. // if(xi.distanceTo(xj) > si.boundingSphereRadius + sj.boundingSphereRadius){
  11878. // return;
  11879. // }
  11880. // // Construct a temp hull for each triangle
  11881. // var hullB = new ConvexPolyhedron();
  11882. // hullB.faces = [[0,1,2]];
  11883. // var va = new Vec3();
  11884. // var vb = new Vec3();
  11885. // var vc = new Vec3();
  11886. // hullB.vertices = [
  11887. // va,
  11888. // vb,
  11889. // vc
  11890. // ];
  11891. // for (var i = 0; i < sj.indices.length / 3; i++) {
  11892. // var triangleNormal = new Vec3();
  11893. // sj.getNormal(i, triangleNormal);
  11894. // hullB.faceNormals = [triangleNormal];
  11895. // sj.getTriangleVertices(i, va, vb, vc);
  11896. // var d = si.testSepAxis(triangleNormal, hullB, xi, qi, xj, qj);
  11897. // if(!d){
  11898. // triangleNormal.scale(-1, triangleNormal);
  11899. // d = si.testSepAxis(triangleNormal, hullB, xi, qi, xj, qj);
  11900. // if(!d){
  11901. // continue;
  11902. // }
  11903. // }
  11904. // var res = [];
  11905. // var q = convexConvex_q;
  11906. // si.clipAgainstHull(xi,qi,hullB,xj,qj,triangleNormal,-100,100,res);
  11907. // for(var j = 0; j !== res.length; j++){
  11908. // var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj),
  11909. // ri = r.ri,
  11910. // rj = r.rj;
  11911. // r.ni.copy(triangleNormal);
  11912. // r.ni.negate(r.ni);
  11913. // res[j].normal.negate(q);
  11914. // q.mult(res[j].depth, q);
  11915. // res[j].point.vadd(q, ri);
  11916. // rj.copy(res[j].point);
  11917. // // Contact points are in world coordinates. Transform back to relative
  11918. // ri.vsub(xi,ri);
  11919. // rj.vsub(xj,rj);
  11920. // // Make relative to bodies
  11921. // ri.vadd(xi, ri);
  11922. // ri.vsub(bi.position, ri);
  11923. // rj.vadd(xj, rj);
  11924. // rj.vsub(bj.position, rj);
  11925. // result.push(r);
  11926. // }
  11927. // }
  11928. // };
  11929. var particlePlane_normal = new Vec3();
  11930. var particlePlane_relpos = new Vec3();
  11931. var particlePlane_projected = new Vec3();
  11932. /**
  11933. * @method particlePlane
  11934. * @param {Array} result
  11935. * @param {Shape} si
  11936. * @param {Shape} sj
  11937. * @param {Vec3} xi
  11938. * @param {Vec3} xj
  11939. * @param {Quaternion} qi
  11940. * @param {Quaternion} qj
  11941. * @param {Body} bi
  11942. * @param {Body} bj
  11943. */
  11944. Narrowphase.prototype[Shape.types.PLANE | Shape.types.PARTICLE] =
  11945. Narrowphase.prototype.planeParticle = function(sj,si,xj,xi,qj,qi,bj,bi,rsi,rsj,justTest){
  11946. var normal = particlePlane_normal;
  11947. normal.set(0,0,1);
  11948. bj.quaternion.vmult(normal,normal); // Turn normal according to plane orientation
  11949. var relpos = particlePlane_relpos;
  11950. xi.vsub(bj.position,relpos);
  11951. var dot = normal.dot(relpos);
  11952. if(dot <= 0.0){
  11953. if(justTest){
  11954. return true;
  11955. }
  11956. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  11957. r.ni.copy(normal); // Contact normal is the plane normal
  11958. r.ni.negate(r.ni);
  11959. r.ri.set(0,0,0); // Center of particle
  11960. // Get particle position projected on plane
  11961. var projected = particlePlane_projected;
  11962. normal.mult(normal.dot(xi),projected);
  11963. xi.vsub(projected,projected);
  11964. //projected.vadd(bj.position,projected);
  11965. // rj is now the projected world position minus plane position
  11966. r.rj.copy(projected);
  11967. this.result.push(r);
  11968. this.createFrictionEquationsFromContact(r, this.frictionResult);
  11969. }
  11970. };
  11971. var particleSphere_normal = new Vec3();
  11972. /**
  11973. * @method particleSphere
  11974. * @param {Array} result
  11975. * @param {Shape} si
  11976. * @param {Shape} sj
  11977. * @param {Vec3} xi
  11978. * @param {Vec3} xj
  11979. * @param {Quaternion} qi
  11980. * @param {Quaternion} qj
  11981. * @param {Body} bi
  11982. * @param {Body} bj
  11983. */
  11984. Narrowphase.prototype[Shape.types.PARTICLE | Shape.types.SPHERE] =
  11985. Narrowphase.prototype.sphereParticle = function(sj,si,xj,xi,qj,qi,bj,bi,rsi,rsj,justTest){
  11986. // The normal is the unit vector from sphere center to particle center
  11987. var normal = particleSphere_normal;
  11988. normal.set(0,0,1);
  11989. xi.vsub(xj,normal);
  11990. var lengthSquared = normal.norm2();
  11991. if(lengthSquared <= sj.radius * sj.radius){
  11992. if(justTest){
  11993. return true;
  11994. }
  11995. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  11996. normal.normalize();
  11997. r.rj.copy(normal);
  11998. r.rj.mult(sj.radius,r.rj);
  11999. r.ni.copy(normal); // Contact normal
  12000. r.ni.negate(r.ni);
  12001. r.ri.set(0,0,0); // Center of particle
  12002. this.result.push(r);
  12003. this.createFrictionEquationsFromContact(r, this.frictionResult);
  12004. }
  12005. };
  12006. // WIP
  12007. var cqj = new Quaternion();
  12008. var convexParticle_local = new Vec3();
  12009. var convexParticle_normal = new Vec3();
  12010. var convexParticle_penetratedFaceNormal = new Vec3();
  12011. var convexParticle_vertexToParticle = new Vec3();
  12012. var convexParticle_worldPenetrationVec = new Vec3();
  12013. /**
  12014. * @method convexParticle
  12015. * @param {Array} result
  12016. * @param {Shape} si
  12017. * @param {Shape} sj
  12018. * @param {Vec3} xi
  12019. * @param {Vec3} xj
  12020. * @param {Quaternion} qi
  12021. * @param {Quaternion} qj
  12022. * @param {Body} bi
  12023. * @param {Body} bj
  12024. */
  12025. Narrowphase.prototype[Shape.types.PARTICLE | Shape.types.CONVEXPOLYHEDRON] =
  12026. Narrowphase.prototype.convexParticle = function(sj,si,xj,xi,qj,qi,bj,bi,rsi,rsj,justTest){
  12027. var penetratedFaceIndex = -1;
  12028. var penetratedFaceNormal = convexParticle_penetratedFaceNormal;
  12029. var worldPenetrationVec = convexParticle_worldPenetrationVec;
  12030. var minPenetration = null;
  12031. var numDetectedFaces = 0;
  12032. // Convert particle position xi to local coords in the convex
  12033. var local = convexParticle_local;
  12034. local.copy(xi);
  12035. local.vsub(xj,local); // Convert position to relative the convex origin
  12036. qj.conjugate(cqj);
  12037. cqj.vmult(local,local);
  12038. if(sj.pointIsInside(local)){
  12039. if(sj.worldVerticesNeedsUpdate){
  12040. sj.computeWorldVertices(xj,qj);
  12041. }
  12042. if(sj.worldFaceNormalsNeedsUpdate){
  12043. sj.computeWorldFaceNormals(qj);
  12044. }
  12045. // For each world polygon in the polyhedra
  12046. for(var i=0,nfaces=sj.faces.length; i!==nfaces; i++){
  12047. // Construct world face vertices
  12048. var verts = [ sj.worldVertices[ sj.faces[i][0] ] ];
  12049. var normal = sj.worldFaceNormals[i];
  12050. // Check how much the particle penetrates the polygon plane.
  12051. xi.vsub(verts[0],convexParticle_vertexToParticle);
  12052. var penetration = -normal.dot(convexParticle_vertexToParticle);
  12053. if(minPenetration===null || Math.abs(penetration)<Math.abs(minPenetration)){
  12054. if(justTest){
  12055. return true;
  12056. }
  12057. minPenetration = penetration;
  12058. penetratedFaceIndex = i;
  12059. penetratedFaceNormal.copy(normal);
  12060. numDetectedFaces++;
  12061. }
  12062. }
  12063. if(penetratedFaceIndex!==-1){
  12064. // Setup contact
  12065. var r = this.createContactEquation(bi,bj,si,sj,rsi,rsj);
  12066. penetratedFaceNormal.mult(minPenetration, worldPenetrationVec);
  12067. // rj is the particle position projected to the face
  12068. worldPenetrationVec.vadd(xi,worldPenetrationVec);
  12069. worldPenetrationVec.vsub(xj,worldPenetrationVec);
  12070. r.rj.copy(worldPenetrationVec);
  12071. //var projectedToFace = xi.vsub(xj).vadd(worldPenetrationVec);
  12072. //projectedToFace.copy(r.rj);
  12073. //qj.vmult(r.rj,r.rj);
  12074. penetratedFaceNormal.negate( r.ni ); // Contact normal
  12075. r.ri.set(0,0,0); // Center of particle
  12076. var ri = r.ri,
  12077. rj = r.rj;
  12078. // Make relative to bodies
  12079. ri.vadd(xi, ri);
  12080. ri.vsub(bi.position, ri);
  12081. rj.vadd(xj, rj);
  12082. rj.vsub(bj.position, rj);
  12083. this.result.push(r);
  12084. this.createFrictionEquationsFromContact(r, this.frictionResult);
  12085. } else {
  12086. console.warn("Point found inside convex, but did not find penetrating face!");
  12087. }
  12088. }
  12089. };
  12090. Narrowphase.prototype[Shape.types.BOX | Shape.types.HEIGHTFIELD] =
  12091. Narrowphase.prototype.boxHeightfield = function (si,sj,xi,xj,qi,qj,bi,bj,rsi,rsj,justTest){
  12092. si.convexPolyhedronRepresentation.material = si.material;
  12093. si.convexPolyhedronRepresentation.collisionResponse = si.collisionResponse;
  12094. return this.convexHeightfield(si.convexPolyhedronRepresentation,sj,xi,xj,qi,qj,bi,bj,si,sj,justTest);
  12095. };
  12096. var convexHeightfield_tmp1 = new Vec3();
  12097. var convexHeightfield_tmp2 = new Vec3();
  12098. var convexHeightfield_faceList = [0];
  12099. /**
  12100. * @method convexHeightfield
  12101. */
  12102. Narrowphase.prototype[Shape.types.CONVEXPOLYHEDRON | Shape.types.HEIGHTFIELD] =
  12103. Narrowphase.prototype.convexHeightfield = function (
  12104. convexShape,
  12105. hfShape,
  12106. convexPos,
  12107. hfPos,
  12108. convexQuat,
  12109. hfQuat,
  12110. convexBody,
  12111. hfBody,
  12112. rsi,
  12113. rsj,
  12114. justTest
  12115. ){
  12116. var data = hfShape.data,
  12117. w = hfShape.elementSize,
  12118. radius = convexShape.boundingSphereRadius,
  12119. worldPillarOffset = convexHeightfield_tmp2,
  12120. faceList = convexHeightfield_faceList;
  12121. // Get sphere position to heightfield local!
  12122. var localConvexPos = convexHeightfield_tmp1;
  12123. Transform.pointToLocalFrame(hfPos, hfQuat, convexPos, localConvexPos);
  12124. // Get the index of the data points to test against
  12125. var iMinX = Math.floor((localConvexPos.x - radius) / w) - 1,
  12126. iMaxX = Math.ceil((localConvexPos.x + radius) / w) + 1,
  12127. iMinY = Math.floor((localConvexPos.y - radius) / w) - 1,
  12128. iMaxY = Math.ceil((localConvexPos.y + radius) / w) + 1;
  12129. // Bail out if we are out of the terrain
  12130. if(iMaxX < 0 || iMaxY < 0 || iMinX > data.length || iMinY > data[0].length){
  12131. return;
  12132. }
  12133. // Clamp index to edges
  12134. if(iMinX < 0){ iMinX = 0; }
  12135. if(iMaxX < 0){ iMaxX = 0; }
  12136. if(iMinY < 0){ iMinY = 0; }
  12137. if(iMaxY < 0){ iMaxY = 0; }
  12138. if(iMinX >= data.length){ iMinX = data.length - 1; }
  12139. if(iMaxX >= data.length){ iMaxX = data.length - 1; }
  12140. if(iMaxY >= data[0].length){ iMaxY = data[0].length - 1; }
  12141. if(iMinY >= data[0].length){ iMinY = data[0].length - 1; }
  12142. var minMax = [];
  12143. hfShape.getRectMinMax(iMinX, iMinY, iMaxX, iMaxY, minMax);
  12144. var min = minMax[0];
  12145. var max = minMax[1];
  12146. // Bail out if we're cant touch the bounding height box
  12147. if(localConvexPos.z - radius > max || localConvexPos.z + radius < min){
  12148. return;
  12149. }
  12150. for(var i = iMinX; i < iMaxX; i++){
  12151. for(var j = iMinY; j < iMaxY; j++){
  12152. var intersecting = false;
  12153. // Lower triangle
  12154. hfShape.getConvexTrianglePillar(i, j, false);
  12155. Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
  12156. if (convexPos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + convexShape.boundingSphereRadius) {
  12157. intersecting = this.convexConvex(convexShape, hfShape.pillarConvex, convexPos, worldPillarOffset, convexQuat, hfQuat, convexBody, hfBody, null, null, justTest, faceList, null);
  12158. }
  12159. if(justTest && intersecting){
  12160. return true;
  12161. }
  12162. // Upper triangle
  12163. hfShape.getConvexTrianglePillar(i, j, true);
  12164. Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
  12165. if (convexPos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + convexShape.boundingSphereRadius) {
  12166. intersecting = this.convexConvex(convexShape, hfShape.pillarConvex, convexPos, worldPillarOffset, convexQuat, hfQuat, convexBody, hfBody, null, null, justTest, faceList, null);
  12167. }
  12168. if(justTest && intersecting){
  12169. return true;
  12170. }
  12171. }
  12172. }
  12173. };
  12174. var sphereHeightfield_tmp1 = new Vec3();
  12175. var sphereHeightfield_tmp2 = new Vec3();
  12176. /**
  12177. * @method sphereHeightfield
  12178. */
  12179. Narrowphase.prototype[Shape.types.SPHERE | Shape.types.HEIGHTFIELD] =
  12180. Narrowphase.prototype.sphereHeightfield = function (
  12181. sphereShape,
  12182. hfShape,
  12183. spherePos,
  12184. hfPos,
  12185. sphereQuat,
  12186. hfQuat,
  12187. sphereBody,
  12188. hfBody,
  12189. rsi,
  12190. rsj,
  12191. justTest
  12192. ){
  12193. var data = hfShape.data,
  12194. radius = sphereShape.radius,
  12195. w = hfShape.elementSize,
  12196. worldPillarOffset = sphereHeightfield_tmp2;
  12197. // Get sphere position to heightfield local!
  12198. var localSpherePos = sphereHeightfield_tmp1;
  12199. Transform.pointToLocalFrame(hfPos, hfQuat, spherePos, localSpherePos);
  12200. // Get the index of the data points to test against
  12201. var iMinX = Math.floor((localSpherePos.x - radius) / w) - 1,
  12202. iMaxX = Math.ceil((localSpherePos.x + radius) / w) + 1,
  12203. iMinY = Math.floor((localSpherePos.y - radius) / w) - 1,
  12204. iMaxY = Math.ceil((localSpherePos.y + radius) / w) + 1;
  12205. // Bail out if we are out of the terrain
  12206. if(iMaxX < 0 || iMaxY < 0 || iMinX > data.length || iMaxY > data[0].length){
  12207. return;
  12208. }
  12209. // Clamp index to edges
  12210. if(iMinX < 0){ iMinX = 0; }
  12211. if(iMaxX < 0){ iMaxX = 0; }
  12212. if(iMinY < 0){ iMinY = 0; }
  12213. if(iMaxY < 0){ iMaxY = 0; }
  12214. if(iMinX >= data.length){ iMinX = data.length - 1; }
  12215. if(iMaxX >= data.length){ iMaxX = data.length - 1; }
  12216. if(iMaxY >= data[0].length){ iMaxY = data[0].length - 1; }
  12217. if(iMinY >= data[0].length){ iMinY = data[0].length - 1; }
  12218. var minMax = [];
  12219. hfShape.getRectMinMax(iMinX, iMinY, iMaxX, iMaxY, minMax);
  12220. var min = minMax[0];
  12221. var max = minMax[1];
  12222. // Bail out if we're cant touch the bounding height box
  12223. if(localSpherePos.z - radius > max || localSpherePos.z + radius < min){
  12224. return;
  12225. }
  12226. var result = this.result;
  12227. for(var i = iMinX; i < iMaxX; i++){
  12228. for(var j = iMinY; j < iMaxY; j++){
  12229. var numContactsBefore = result.length;
  12230. var intersecting = false;
  12231. // Lower triangle
  12232. hfShape.getConvexTrianglePillar(i, j, false);
  12233. Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
  12234. if (spherePos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + sphereShape.boundingSphereRadius) {
  12235. intersecting = this.sphereConvex(sphereShape, hfShape.pillarConvex, spherePos, worldPillarOffset, sphereQuat, hfQuat, sphereBody, hfBody, sphereShape, hfShape, justTest);
  12236. }
  12237. if(justTest && intersecting){
  12238. return true;
  12239. }
  12240. // Upper triangle
  12241. hfShape.getConvexTrianglePillar(i, j, true);
  12242. Transform.pointToWorldFrame(hfPos, hfQuat, hfShape.pillarOffset, worldPillarOffset);
  12243. if (spherePos.distanceTo(worldPillarOffset) < hfShape.pillarConvex.boundingSphereRadius + sphereShape.boundingSphereRadius) {
  12244. intersecting = this.sphereConvex(sphereShape, hfShape.pillarConvex, spherePos, worldPillarOffset, sphereQuat, hfQuat, sphereBody, hfBody, sphereShape, hfShape, justTest);
  12245. }
  12246. if(justTest && intersecting){
  12247. return true;
  12248. }
  12249. var numContacts = result.length - numContactsBefore;
  12250. if(numContacts > 2){
  12251. return;
  12252. }
  12253. /*
  12254. // Skip all but 1
  12255. for (var k = 0; k < numContacts - 1; k++) {
  12256. result.pop();
  12257. }
  12258. */
  12259. }
  12260. }
  12261. };
  12262. },{"../collision/AABB":15,"../collision/Ray":22,"../equations/ContactEquation":32,"../equations/FrictionEquation":34,"../math/Quaternion":41,"../math/Transform":42,"../math/Vec3":43,"../objects/Body":44,"../shapes/ConvexPolyhedron":51,"../shapes/Shape":56,"../solver/Solver":60,"../utils/Vec3Pool":67}],69:[function(require,module,exports){
  12263. /* global performance */
  12264. module.exports = World;
  12265. var Shape = require('../shapes/Shape');
  12266. var Vec3 = require('../math/Vec3');
  12267. var Quaternion = require('../math/Quaternion');
  12268. var GSSolver = require('../solver/GSSolver');
  12269. var ContactEquation = require('../equations/ContactEquation');
  12270. var FrictionEquation = require('../equations/FrictionEquation');
  12271. var Narrowphase = require('./Narrowphase');
  12272. var EventTarget = require('../utils/EventTarget');
  12273. var ArrayCollisionMatrix = require('../collision/ArrayCollisionMatrix');
  12274. var OverlapKeeper = require('../collision/OverlapKeeper');
  12275. var Material = require('../material/Material');
  12276. var ContactMaterial = require('../material/ContactMaterial');
  12277. var Body = require('../objects/Body');
  12278. var TupleDictionary = require('../utils/TupleDictionary');
  12279. var RaycastResult = require('../collision/RaycastResult');
  12280. var AABB = require('../collision/AABB');
  12281. var Ray = require('../collision/Ray');
  12282. var NaiveBroadphase = require('../collision/NaiveBroadphase');
  12283. /**
  12284. * The physics world
  12285. * @class World
  12286. * @constructor
  12287. * @extends EventTarget
  12288. * @param {object} [options]
  12289. * @param {Vec3} [options.gravity]
  12290. * @param {boolean} [options.allowSleep]
  12291. * @param {Broadphase} [options.broadphase]
  12292. * @param {Solver} [options.solver]
  12293. * @param {boolean} [options.quatNormalizeFast]
  12294. * @param {number} [options.quatNormalizeSkip]
  12295. */
  12296. function World(options){
  12297. options = options || {};
  12298. EventTarget.apply(this);
  12299. /**
  12300. * 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.
  12301. * @property {Number} dt
  12302. */
  12303. this.dt = -1;
  12304. /**
  12305. * Makes bodies go to sleep when they've been inactive
  12306. * @property allowSleep
  12307. * @type {Boolean}
  12308. * @default false
  12309. */
  12310. this.allowSleep = !!options.allowSleep;
  12311. /**
  12312. * All the current contacts (instances of ContactEquation) in the world.
  12313. * @property contacts
  12314. * @type {Array}
  12315. */
  12316. this.contacts = [];
  12317. this.frictionEquations = [];
  12318. /**
  12319. * 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).
  12320. * @property quatNormalizeSkip
  12321. * @type {Number}
  12322. * @default 0
  12323. */
  12324. this.quatNormalizeSkip = options.quatNormalizeSkip !== undefined ? options.quatNormalizeSkip : 0;
  12325. /**
  12326. * Set to true to use fast quaternion normalization. It is often enough accurate to use. If bodies tend to explode, set to false.
  12327. * @property quatNormalizeFast
  12328. * @type {Boolean}
  12329. * @see Quaternion.normalizeFast
  12330. * @see Quaternion.normalize
  12331. * @default false
  12332. */
  12333. this.quatNormalizeFast = options.quatNormalizeFast !== undefined ? options.quatNormalizeFast : false;
  12334. /**
  12335. * The wall-clock time since simulation start
  12336. * @property time
  12337. * @type {Number}
  12338. */
  12339. this.time = 0.0;
  12340. /**
  12341. * Number of timesteps taken since start
  12342. * @property stepnumber
  12343. * @type {Number}
  12344. */
  12345. this.stepnumber = 0;
  12346. /// Default and last timestep sizes
  12347. this.default_dt = 1/60;
  12348. this.nextId = 0;
  12349. /**
  12350. * @property gravity
  12351. * @type {Vec3}
  12352. */
  12353. this.gravity = new Vec3();
  12354. if(options.gravity){
  12355. this.gravity.copy(options.gravity);
  12356. }
  12357. /**
  12358. * The broadphase algorithm to use. Default is NaiveBroadphase
  12359. * @property broadphase
  12360. * @type {Broadphase}
  12361. */
  12362. this.broadphase = options.broadphase !== undefined ? options.broadphase : new NaiveBroadphase();
  12363. /**
  12364. * @property bodies
  12365. * @type {Array}
  12366. */
  12367. this.bodies = [];
  12368. /**
  12369. * The solver algorithm to use. Default is GSSolver
  12370. * @property solver
  12371. * @type {Solver}
  12372. */
  12373. this.solver = options.solver !== undefined ? options.solver : new GSSolver();
  12374. /**
  12375. * @property constraints
  12376. * @type {Array}
  12377. */
  12378. this.constraints = [];
  12379. /**
  12380. * @property narrowphase
  12381. * @type {Narrowphase}
  12382. */
  12383. this.narrowphase = new Narrowphase(this);
  12384. /**
  12385. * @property {ArrayCollisionMatrix} collisionMatrix
  12386. * @type {ArrayCollisionMatrix}
  12387. */
  12388. this.collisionMatrix = new ArrayCollisionMatrix();
  12389. /**
  12390. * CollisionMatrix from the previous step.
  12391. * @property {ArrayCollisionMatrix} collisionMatrixPrevious
  12392. * @type {ArrayCollisionMatrix}
  12393. */
  12394. this.collisionMatrixPrevious = new ArrayCollisionMatrix();
  12395. this.bodyOverlapKeeper = new OverlapKeeper();
  12396. this.shapeOverlapKeeper = new OverlapKeeper();
  12397. /**
  12398. * All added materials
  12399. * @property materials
  12400. * @type {Array}
  12401. */
  12402. this.materials = [];
  12403. /**
  12404. * @property contactmaterials
  12405. * @type {Array}
  12406. */
  12407. this.contactmaterials = [];
  12408. /**
  12409. * Used to look up a ContactMaterial given two instances of Material.
  12410. * @property {TupleDictionary} contactMaterialTable
  12411. */
  12412. this.contactMaterialTable = new TupleDictionary();
  12413. this.defaultMaterial = new Material("default");
  12414. /**
  12415. * This contact material is used if no suitable contactmaterial is found for a contact.
  12416. * @property defaultContactMaterial
  12417. * @type {ContactMaterial}
  12418. */
  12419. this.defaultContactMaterial = new ContactMaterial(this.defaultMaterial, this.defaultMaterial, { friction: 0.3, restitution: 0.0 });
  12420. /**
  12421. * @property doProfiling
  12422. * @type {Boolean}
  12423. */
  12424. this.doProfiling = false;
  12425. /**
  12426. * @property profile
  12427. * @type {Object}
  12428. */
  12429. this.profile = {
  12430. solve:0,
  12431. makeContactConstraints:0,
  12432. broadphase:0,
  12433. integrate:0,
  12434. narrowphase:0,
  12435. };
  12436. /**
  12437. * Time accumulator for interpolation. See http://gafferongames.com/game-physics/fix-your-timestep/
  12438. * @property {Number} accumulator
  12439. */
  12440. this.accumulator = 0;
  12441. /**
  12442. * @property subsystems
  12443. * @type {Array}
  12444. */
  12445. this.subsystems = [];
  12446. /**
  12447. * Dispatched after a body has been added to the world.
  12448. * @event addBody
  12449. * @param {Body} body The body that has been added to the world.
  12450. */
  12451. this.addBodyEvent = {
  12452. type:"addBody",
  12453. body : null
  12454. };
  12455. /**
  12456. * Dispatched after a body has been removed from the world.
  12457. * @event removeBody
  12458. * @param {Body} body The body that has been removed from the world.
  12459. */
  12460. this.removeBodyEvent = {
  12461. type:"removeBody",
  12462. body : null
  12463. };
  12464. this.idToBodyMap = {};
  12465. this.broadphase.setWorld(this);
  12466. }
  12467. World.prototype = new EventTarget();
  12468. // Temp stuff
  12469. var tmpAABB1 = new AABB();
  12470. var tmpArray1 = [];
  12471. var tmpRay = new Ray();
  12472. /**
  12473. * Get the contact material between materials m1 and m2
  12474. * @method getContactMaterial
  12475. * @param {Material} m1
  12476. * @param {Material} m2
  12477. * @return {ContactMaterial} The contact material if it was found.
  12478. */
  12479. World.prototype.getContactMaterial = function(m1,m2){
  12480. return this.contactMaterialTable.get(m1.id,m2.id); //this.contactmaterials[this.mats2cmat[i+j*this.materials.length]];
  12481. };
  12482. /**
  12483. * Get number of objects in the world.
  12484. * @method numObjects
  12485. * @return {Number}
  12486. * @deprecated
  12487. */
  12488. World.prototype.numObjects = function(){
  12489. return this.bodies.length;
  12490. };
  12491. /**
  12492. * Store old collision state info
  12493. * @method collisionMatrixTick
  12494. */
  12495. World.prototype.collisionMatrixTick = function(){
  12496. var temp = this.collisionMatrixPrevious;
  12497. this.collisionMatrixPrevious = this.collisionMatrix;
  12498. this.collisionMatrix = temp;
  12499. this.collisionMatrix.reset();
  12500. this.bodyOverlapKeeper.tick();
  12501. this.shapeOverlapKeeper.tick();
  12502. };
  12503. /**
  12504. * Add a rigid body to the simulation.
  12505. * @method add
  12506. * @param {Body} body
  12507. * @todo If the simulation has not yet started, why recrete and copy arrays for each body? Accumulate in dynamic arrays in this case.
  12508. * @todo Adding an array of bodies should be possible. This would save some loops too
  12509. * @deprecated Use .addBody instead
  12510. */
  12511. World.prototype.add = World.prototype.addBody = function(body){
  12512. if(this.bodies.indexOf(body) !== -1){
  12513. return;
  12514. }
  12515. body.index = this.bodies.length;
  12516. this.bodies.push(body);
  12517. body.world = this;
  12518. body.initPosition.copy(body.position);
  12519. body.initVelocity.copy(body.velocity);
  12520. body.timeLastSleepy = this.time;
  12521. if(body instanceof Body){
  12522. body.initAngularVelocity.copy(body.angularVelocity);
  12523. body.initQuaternion.copy(body.quaternion);
  12524. }
  12525. this.collisionMatrix.setNumObjects(this.bodies.length);
  12526. this.addBodyEvent.body = body;
  12527. this.idToBodyMap[body.id] = body;
  12528. this.dispatchEvent(this.addBodyEvent);
  12529. };
  12530. /**
  12531. * Add a constraint to the simulation.
  12532. * @method addConstraint
  12533. * @param {Constraint} c
  12534. */
  12535. World.prototype.addConstraint = function(c){
  12536. this.constraints.push(c);
  12537. };
  12538. /**
  12539. * Removes a constraint
  12540. * @method removeConstraint
  12541. * @param {Constraint} c
  12542. */
  12543. World.prototype.removeConstraint = function(c){
  12544. var idx = this.constraints.indexOf(c);
  12545. if(idx!==-1){
  12546. this.constraints.splice(idx,1);
  12547. }
  12548. };
  12549. /**
  12550. * Raycast test
  12551. * @method rayTest
  12552. * @param {Vec3} from
  12553. * @param {Vec3} to
  12554. * @param {RaycastResult} result
  12555. * @deprecated Use .raycastAll, .raycastClosest or .raycastAny instead.
  12556. */
  12557. World.prototype.rayTest = function(from, to, result){
  12558. if(result instanceof RaycastResult){
  12559. // Do raycastclosest
  12560. this.raycastClosest(from, to, {
  12561. skipBackfaces: true
  12562. }, result);
  12563. } else {
  12564. // Do raycastAll
  12565. this.raycastAll(from, to, {
  12566. skipBackfaces: true
  12567. }, result);
  12568. }
  12569. };
  12570. /**
  12571. * Ray cast against all bodies. The provided callback will be executed for each hit with a RaycastResult as single argument.
  12572. * @method raycastAll
  12573. * @param {Vec3} from
  12574. * @param {Vec3} to
  12575. * @param {Object} options
  12576. * @param {number} [options.collisionFilterMask=-1]
  12577. * @param {number} [options.collisionFilterGroup=-1]
  12578. * @param {boolean} [options.skipBackfaces=false]
  12579. * @param {boolean} [options.checkCollisionResponse=true]
  12580. * @param {Function} callback
  12581. * @return {boolean} True if any body was hit.
  12582. */
  12583. World.prototype.raycastAll = function(from, to, options, callback){
  12584. options.mode = Ray.ALL;
  12585. options.from = from;
  12586. options.to = to;
  12587. options.callback = callback;
  12588. return tmpRay.intersectWorld(this, options);
  12589. };
  12590. /**
  12591. * Ray cast, and stop at the first result. Note that the order is random - but the method is fast.
  12592. * @method raycastAny
  12593. * @param {Vec3} from
  12594. * @param {Vec3} to
  12595. * @param {Object} options
  12596. * @param {number} [options.collisionFilterMask=-1]
  12597. * @param {number} [options.collisionFilterGroup=-1]
  12598. * @param {boolean} [options.skipBackfaces=false]
  12599. * @param {boolean} [options.checkCollisionResponse=true]
  12600. * @param {RaycastResult} result
  12601. * @return {boolean} True if any body was hit.
  12602. */
  12603. World.prototype.raycastAny = function(from, to, options, result){
  12604. options.mode = Ray.ANY;
  12605. options.from = from;
  12606. options.to = to;
  12607. options.result = result;
  12608. return tmpRay.intersectWorld(this, options);
  12609. };
  12610. /**
  12611. * Ray cast, and return information of the closest hit.
  12612. * @method raycastClosest
  12613. * @param {Vec3} from
  12614. * @param {Vec3} to
  12615. * @param {Object} options
  12616. * @param {number} [options.collisionFilterMask=-1]
  12617. * @param {number} [options.collisionFilterGroup=-1]
  12618. * @param {boolean} [options.skipBackfaces=false]
  12619. * @param {boolean} [options.checkCollisionResponse=true]
  12620. * @param {RaycastResult} result
  12621. * @return {boolean} True if any body was hit.
  12622. */
  12623. World.prototype.raycastClosest = function(from, to, options, result){
  12624. options.mode = Ray.CLOSEST;
  12625. options.from = from;
  12626. options.to = to;
  12627. options.result = result;
  12628. return tmpRay.intersectWorld(this, options);
  12629. };
  12630. /**
  12631. * Remove a rigid body from the simulation.
  12632. * @method remove
  12633. * @param {Body} body
  12634. * @deprecated Use .removeBody instead
  12635. */
  12636. World.prototype.remove = function(body){
  12637. body.world = null;
  12638. var n = this.bodies.length - 1,
  12639. bodies = this.bodies,
  12640. idx = bodies.indexOf(body);
  12641. if(idx !== -1){
  12642. bodies.splice(idx, 1); // Todo: should use a garbage free method
  12643. // Recompute index
  12644. for(var i=0; i!==bodies.length; i++){
  12645. bodies[i].index = i;
  12646. }
  12647. this.collisionMatrix.setNumObjects(n);
  12648. this.removeBodyEvent.body = body;
  12649. delete this.idToBodyMap[body.id];
  12650. this.dispatchEvent(this.removeBodyEvent);
  12651. }
  12652. };
  12653. /**
  12654. * Remove a rigid body from the simulation.
  12655. * @method removeBody
  12656. * @param {Body} body
  12657. */
  12658. World.prototype.removeBody = World.prototype.remove;
  12659. World.prototype.getBodyById = function(id){
  12660. return this.idToBodyMap[id];
  12661. };
  12662. // TODO Make a faster map
  12663. World.prototype.getShapeById = function(id){
  12664. var bodies = this.bodies;
  12665. for(var i=0, bl = bodies.length; i<bl; i++){
  12666. var shapes = bodies[i].shapes;
  12667. for (var j = 0, sl = shapes.length; j < sl; j++) {
  12668. var shape = shapes[j];
  12669. if(shape.id === id){
  12670. return shape;
  12671. }
  12672. }
  12673. }
  12674. };
  12675. /**
  12676. * Adds a material to the World.
  12677. * @method addMaterial
  12678. * @param {Material} m
  12679. * @todo Necessary?
  12680. */
  12681. World.prototype.addMaterial = function(m){
  12682. this.materials.push(m);
  12683. };
  12684. /**
  12685. * Adds a contact material to the World
  12686. * @method addContactMaterial
  12687. * @param {ContactMaterial} cmat
  12688. */
  12689. World.prototype.addContactMaterial = function(cmat) {
  12690. // Add contact material
  12691. this.contactmaterials.push(cmat);
  12692. // Add current contact material to the material table
  12693. this.contactMaterialTable.set(cmat.materials[0].id,cmat.materials[1].id,cmat);
  12694. };
  12695. // performance.now()
  12696. if(typeof performance === 'undefined'){
  12697. performance = {};
  12698. }
  12699. if(!performance.now){
  12700. var nowOffset = Date.now();
  12701. if (performance.timing && performance.timing.navigationStart){
  12702. nowOffset = performance.timing.navigationStart;
  12703. }
  12704. performance.now = function(){
  12705. return Date.now() - nowOffset;
  12706. };
  12707. }
  12708. var step_tmp1 = new Vec3();
  12709. /**
  12710. * Step the physics world forward in time.
  12711. *
  12712. * 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.
  12713. *
  12714. * @method step
  12715. * @param {Number} dt The fixed time step size to use.
  12716. * @param {Number} [timeSinceLastCalled] The time elapsed since the function was last called.
  12717. * @param {Number} [maxSubSteps=10] Maximum number of fixed steps to take per function call.
  12718. *
  12719. * @example
  12720. * // fixed timestepping without interpolation
  12721. * world.step(1/60);
  12722. *
  12723. * @see http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World
  12724. */
  12725. World.prototype.step = function(dt, timeSinceLastCalled, maxSubSteps){
  12726. maxSubSteps = maxSubSteps || 10;
  12727. timeSinceLastCalled = timeSinceLastCalled || 0;
  12728. if(timeSinceLastCalled === 0){ // Fixed, simple stepping
  12729. this.internalStep(dt);
  12730. // Increment time
  12731. this.time += dt;
  12732. } else {
  12733. this.accumulator += timeSinceLastCalled;
  12734. var substeps = 0;
  12735. while (this.accumulator >= dt && substeps < maxSubSteps) {
  12736. // Do fixed steps to catch up
  12737. this.internalStep(dt);
  12738. this.accumulator -= dt;
  12739. substeps++;
  12740. }
  12741. var t = (this.accumulator % dt) / dt;
  12742. for(var j=0; j !== this.bodies.length; j++){
  12743. var b = this.bodies[j];
  12744. b.previousPosition.lerp(b.position, t, b.interpolatedPosition);
  12745. b.previousQuaternion.slerp(b.quaternion, t, b.interpolatedQuaternion);
  12746. b.previousQuaternion.normalize();
  12747. }
  12748. this.time += timeSinceLastCalled;
  12749. }
  12750. };
  12751. var
  12752. /**
  12753. * Dispatched after the world has stepped forward in time.
  12754. * @event postStep
  12755. */
  12756. World_step_postStepEvent = {type:"postStep"}, // Reusable event objects to save memory
  12757. /**
  12758. * Dispatched before the world steps forward in time.
  12759. * @event preStep
  12760. */
  12761. World_step_preStepEvent = {type:"preStep"},
  12762. World_step_collideEvent = {type:Body.COLLIDE_EVENT_NAME, body:null, contact:null },
  12763. World_step_oldContacts = [], // Pools for unused objects
  12764. World_step_frictionEquationPool = [],
  12765. World_step_p1 = [], // Reusable arrays for collision pairs
  12766. World_step_p2 = [],
  12767. World_step_gvec = new Vec3(), // Temporary vectors and quats
  12768. World_step_vi = new Vec3(),
  12769. World_step_vj = new Vec3(),
  12770. World_step_wi = new Vec3(),
  12771. World_step_wj = new Vec3(),
  12772. World_step_t1 = new Vec3(),
  12773. World_step_t2 = new Vec3(),
  12774. World_step_rixn = new Vec3(),
  12775. World_step_rjxn = new Vec3(),
  12776. World_step_step_q = new Quaternion(),
  12777. World_step_step_w = new Quaternion(),
  12778. World_step_step_wq = new Quaternion(),
  12779. invI_tau_dt = new Vec3();
  12780. World.prototype.internalStep = function(dt){
  12781. this.dt = dt;
  12782. var world = this,
  12783. that = this,
  12784. contacts = this.contacts,
  12785. p1 = World_step_p1,
  12786. p2 = World_step_p2,
  12787. N = this.numObjects(),
  12788. bodies = this.bodies,
  12789. solver = this.solver,
  12790. gravity = this.gravity,
  12791. doProfiling = this.doProfiling,
  12792. profile = this.profile,
  12793. DYNAMIC = Body.DYNAMIC,
  12794. profilingStart,
  12795. constraints = this.constraints,
  12796. frictionEquationPool = World_step_frictionEquationPool,
  12797. gnorm = gravity.norm(),
  12798. gx = gravity.x,
  12799. gy = gravity.y,
  12800. gz = gravity.z,
  12801. i=0;
  12802. if(doProfiling){
  12803. profilingStart = performance.now();
  12804. }
  12805. // Add gravity to all objects
  12806. for(i=0; i!==N; i++){
  12807. var bi = bodies[i];
  12808. if(bi.type === DYNAMIC){ // Only for dynamic bodies
  12809. var f = bi.force, m = bi.mass;
  12810. f.x += m*gx;
  12811. f.y += m*gy;
  12812. f.z += m*gz;
  12813. }
  12814. }
  12815. // Update subsystems
  12816. for(var i=0, Nsubsystems=this.subsystems.length; i!==Nsubsystems; i++){
  12817. this.subsystems[i].update();
  12818. }
  12819. // Collision detection
  12820. if(doProfiling){ profilingStart = performance.now(); }
  12821. p1.length = 0; // Clean up pair arrays from last step
  12822. p2.length = 0;
  12823. this.broadphase.collisionPairs(this,p1,p2);
  12824. if(doProfiling){ profile.broadphase = performance.now() - profilingStart; }
  12825. // Remove constrained pairs with collideConnected == false
  12826. var Nconstraints = constraints.length;
  12827. for(i=0; i!==Nconstraints; i++){
  12828. var c = constraints[i];
  12829. if(!c.collideConnected){
  12830. for(var j = p1.length-1; j>=0; j-=1){
  12831. if( (c.bodyA === p1[j] && c.bodyB === p2[j]) ||
  12832. (c.bodyB === p1[j] && c.bodyA === p2[j])){
  12833. p1.splice(j, 1);
  12834. p2.splice(j, 1);
  12835. }
  12836. }
  12837. }
  12838. }
  12839. this.collisionMatrixTick();
  12840. // Generate contacts
  12841. if(doProfiling){ profilingStart = performance.now(); }
  12842. var oldcontacts = World_step_oldContacts;
  12843. var NoldContacts = contacts.length;
  12844. for(i=0; i!==NoldContacts; i++){
  12845. oldcontacts.push(contacts[i]);
  12846. }
  12847. contacts.length = 0;
  12848. // Transfer FrictionEquation from current list to the pool for reuse
  12849. var NoldFrictionEquations = this.frictionEquations.length;
  12850. for(i=0; i!==NoldFrictionEquations; i++){
  12851. frictionEquationPool.push(this.frictionEquations[i]);
  12852. }
  12853. this.frictionEquations.length = 0;
  12854. this.narrowphase.getContacts(
  12855. p1,
  12856. p2,
  12857. this,
  12858. contacts,
  12859. oldcontacts, // To be reused
  12860. this.frictionEquations,
  12861. frictionEquationPool
  12862. );
  12863. if(doProfiling){
  12864. profile.narrowphase = performance.now() - profilingStart;
  12865. }
  12866. // Loop over all collisions
  12867. if(doProfiling){
  12868. profilingStart = performance.now();
  12869. }
  12870. // Add all friction eqs
  12871. for (var i = 0; i < this.frictionEquations.length; i++) {
  12872. solver.addEquation(this.frictionEquations[i]);
  12873. }
  12874. var ncontacts = contacts.length;
  12875. for(var k=0; k!==ncontacts; k++){
  12876. // Current contact
  12877. var c = contacts[k];
  12878. // Get current collision indeces
  12879. var bi = c.bi,
  12880. bj = c.bj,
  12881. si = c.si,
  12882. sj = c.sj;
  12883. // Get collision properties
  12884. var cm;
  12885. if(bi.material && bj.material){
  12886. cm = this.getContactMaterial(bi.material,bj.material) || this.defaultContactMaterial;
  12887. } else {
  12888. cm = this.defaultContactMaterial;
  12889. }
  12890. // c.enabled = bi.collisionResponse && bj.collisionResponse && si.collisionResponse && sj.collisionResponse;
  12891. var mu = cm.friction;
  12892. // c.restitution = cm.restitution;
  12893. // If friction or restitution were specified in the material, use them
  12894. if(bi.material && bj.material){
  12895. if(bi.material.friction >= 0 && bj.material.friction >= 0){
  12896. mu = bi.material.friction * bj.material.friction;
  12897. }
  12898. if(bi.material.restitution >= 0 && bj.material.restitution >= 0){
  12899. c.restitution = bi.material.restitution * bj.material.restitution;
  12900. }
  12901. }
  12902. // c.setSpookParams(
  12903. // cm.contactEquationStiffness,
  12904. // cm.contactEquationRelaxation,
  12905. // dt
  12906. // );
  12907. solver.addEquation(c);
  12908. // // Add friction constraint equation
  12909. // if(mu > 0){
  12910. // // Create 2 tangent equations
  12911. // var mug = mu * gnorm;
  12912. // var reducedMass = (bi.invMass + bj.invMass);
  12913. // if(reducedMass > 0){
  12914. // reducedMass = 1/reducedMass;
  12915. // }
  12916. // var pool = frictionEquationPool;
  12917. // var c1 = pool.length ? pool.pop() : new FrictionEquation(bi,bj,mug*reducedMass);
  12918. // var c2 = pool.length ? pool.pop() : new FrictionEquation(bi,bj,mug*reducedMass);
  12919. // this.frictionEquations.push(c1, c2);
  12920. // c1.bi = c2.bi = bi;
  12921. // c1.bj = c2.bj = bj;
  12922. // c1.minForce = c2.minForce = -mug*reducedMass;
  12923. // c1.maxForce = c2.maxForce = mug*reducedMass;
  12924. // // Copy over the relative vectors
  12925. // c1.ri.copy(c.ri);
  12926. // c1.rj.copy(c.rj);
  12927. // c2.ri.copy(c.ri);
  12928. // c2.rj.copy(c.rj);
  12929. // // Construct tangents
  12930. // c.ni.tangents(c1.t, c2.t);
  12931. // // Set spook params
  12932. // c1.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, dt);
  12933. // c2.setSpookParams(cm.frictionEquationStiffness, cm.frictionEquationRelaxation, dt);
  12934. // c1.enabled = c2.enabled = c.enabled;
  12935. // // Add equations to solver
  12936. // solver.addEquation(c1);
  12937. // solver.addEquation(c2);
  12938. // }
  12939. if( bi.allowSleep &&
  12940. bi.type === Body.DYNAMIC &&
  12941. bi.sleepState === Body.SLEEPING &&
  12942. bj.sleepState === Body.AWAKE &&
  12943. bj.type !== Body.STATIC
  12944. ){
  12945. var speedSquaredB = bj.velocity.norm2() + bj.angularVelocity.norm2();
  12946. var speedLimitSquaredB = Math.pow(bj.sleepSpeedLimit,2);
  12947. if(speedSquaredB >= speedLimitSquaredB*2){
  12948. bi._wakeUpAfterNarrowphase = true;
  12949. }
  12950. }
  12951. if( bj.allowSleep &&
  12952. bj.type === Body.DYNAMIC &&
  12953. bj.sleepState === Body.SLEEPING &&
  12954. bi.sleepState === Body.AWAKE &&
  12955. bi.type !== Body.STATIC
  12956. ){
  12957. var speedSquaredA = bi.velocity.norm2() + bi.angularVelocity.norm2();
  12958. var speedLimitSquaredA = Math.pow(bi.sleepSpeedLimit,2);
  12959. if(speedSquaredA >= speedLimitSquaredA*2){
  12960. bj._wakeUpAfterNarrowphase = true;
  12961. }
  12962. }
  12963. // Now we know that i and j are in contact. Set collision matrix state
  12964. this.collisionMatrix.set(bi, bj, true);
  12965. if (!this.collisionMatrixPrevious.get(bi, bj)) {
  12966. // First contact!
  12967. // 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.
  12968. World_step_collideEvent.body = bj;
  12969. World_step_collideEvent.contact = c;
  12970. bi.dispatchEvent(World_step_collideEvent);
  12971. World_step_collideEvent.body = bi;
  12972. bj.dispatchEvent(World_step_collideEvent);
  12973. }
  12974. this.bodyOverlapKeeper.set(bi.id, bj.id);
  12975. this.shapeOverlapKeeper.set(si.id, sj.id);
  12976. }
  12977. this.emitContactEvents();
  12978. if(doProfiling){
  12979. profile.makeContactConstraints = performance.now() - profilingStart;
  12980. profilingStart = performance.now();
  12981. }
  12982. // Wake up bodies
  12983. for(i=0; i!==N; i++){
  12984. var bi = bodies[i];
  12985. if(bi._wakeUpAfterNarrowphase){
  12986. bi.wakeUp();
  12987. bi._wakeUpAfterNarrowphase = false;
  12988. }
  12989. }
  12990. // Add user-added constraints
  12991. var Nconstraints = constraints.length;
  12992. for(i=0; i!==Nconstraints; i++){
  12993. var c = constraints[i];
  12994. c.update();
  12995. for(var j=0, Neq=c.equations.length; j!==Neq; j++){
  12996. var eq = c.equations[j];
  12997. solver.addEquation(eq);
  12998. }
  12999. }
  13000. // Solve the constrained system
  13001. solver.solve(dt,this);
  13002. if(doProfiling){
  13003. profile.solve = performance.now() - profilingStart;
  13004. }
  13005. // Remove all contacts from solver
  13006. solver.removeAllEquations();
  13007. // Apply damping, see http://code.google.com/p/bullet/issues/detail?id=74 for details
  13008. var pow = Math.pow;
  13009. for(i=0; i!==N; i++){
  13010. var bi = bodies[i];
  13011. if(bi.type & DYNAMIC){ // Only for dynamic bodies
  13012. var ld = pow(1.0 - bi.linearDamping,dt);
  13013. var v = bi.velocity;
  13014. v.mult(ld,v);
  13015. var av = bi.angularVelocity;
  13016. if(av){
  13017. var ad = pow(1.0 - bi.angularDamping,dt);
  13018. av.mult(ad,av);
  13019. }
  13020. }
  13021. }
  13022. this.dispatchEvent(World_step_preStepEvent);
  13023. // Invoke pre-step callbacks
  13024. for(i=0; i!==N; i++){
  13025. var bi = bodies[i];
  13026. if(bi.preStep){
  13027. bi.preStep.call(bi);
  13028. }
  13029. }
  13030. // Leap frog
  13031. // vnew = v + h*f/m
  13032. // xnew = x + h*vnew
  13033. if(doProfiling){
  13034. profilingStart = performance.now();
  13035. }
  13036. var stepnumber = this.stepnumber;
  13037. var quatNormalize = stepnumber % (this.quatNormalizeSkip + 1) === 0;
  13038. var quatNormalizeFast = this.quatNormalizeFast;
  13039. for(i=0; i!==N; i++){
  13040. bodies[i].integrate(dt, quatNormalize, quatNormalizeFast);
  13041. }
  13042. this.clearForces();
  13043. this.broadphase.dirty = true;
  13044. if(doProfiling){
  13045. profile.integrate = performance.now() - profilingStart;
  13046. }
  13047. // Update world time
  13048. this.time += dt;
  13049. this.stepnumber += 1;
  13050. this.dispatchEvent(World_step_postStepEvent);
  13051. // Invoke post-step callbacks
  13052. for(i=0; i!==N; i++){
  13053. var bi = bodies[i];
  13054. var postStep = bi.postStep;
  13055. if(postStep){
  13056. postStep.call(bi);
  13057. }
  13058. }
  13059. // Sleeping update
  13060. if(this.allowSleep){
  13061. for(i=0; i!==N; i++){
  13062. bodies[i].sleepTick(this.time);
  13063. }
  13064. }
  13065. };
  13066. World.prototype.emitContactEvents = (function(){
  13067. var additions = [];
  13068. var removals = [];
  13069. var beginContactEvent = {
  13070. type: 'beginContact',
  13071. bodyA: null,
  13072. bodyB: null
  13073. };
  13074. var endContactEvent = {
  13075. type: 'endContact',
  13076. bodyA: null,
  13077. bodyB: null
  13078. };
  13079. var beginShapeContactEvent = {
  13080. type: 'beginShapeContact',
  13081. bodyA: null,
  13082. bodyB: null,
  13083. shapeA: null,
  13084. shapeB: null
  13085. };
  13086. var endShapeContactEvent = {
  13087. type: 'endShapeContact',
  13088. bodyA: null,
  13089. bodyB: null,
  13090. shapeA: null,
  13091. shapeB: null
  13092. };
  13093. return function(){
  13094. var hasBeginContact = this.hasAnyEventListener('beginContact');
  13095. var hasEndContact = this.hasAnyEventListener('endContact');
  13096. if(hasBeginContact || hasEndContact){
  13097. this.bodyOverlapKeeper.getDiff(additions, removals);
  13098. }
  13099. if(hasBeginContact){
  13100. for (var i = 0, l = additions.length; i < l; i += 2) {
  13101. beginContactEvent.bodyA = this.getBodyById(additions[i]);
  13102. beginContactEvent.bodyB = this.getBodyById(additions[i+1]);
  13103. this.dispatchEvent(beginContactEvent);
  13104. }
  13105. beginContactEvent.bodyA = beginContactEvent.bodyB = null;
  13106. }
  13107. if(hasEndContact){
  13108. for (var i = 0, l = removals.length; i < l; i += 2) {
  13109. endContactEvent.bodyA = this.getBodyById(removals[i]);
  13110. endContactEvent.bodyB = this.getBodyById(removals[i+1]);
  13111. this.dispatchEvent(endContactEvent);
  13112. }
  13113. endContactEvent.bodyA = endContactEvent.bodyB = null;
  13114. }
  13115. additions.length = removals.length = 0;
  13116. var hasBeginShapeContact = this.hasAnyEventListener('beginShapeContact');
  13117. var hasEndShapeContact = this.hasAnyEventListener('endShapeContact');
  13118. if(hasBeginShapeContact || hasEndShapeContact){
  13119. this.shapeOverlapKeeper.getDiff(additions, removals);
  13120. }
  13121. if(hasBeginShapeContact){
  13122. for (var i = 0, l = additions.length; i < l; i += 2) {
  13123. var shapeA = this.getShapeById(additions[i]);
  13124. var shapeB = this.getShapeById(additions[i+1]);
  13125. beginShapeContactEvent.shapeA = shapeA;
  13126. beginShapeContactEvent.shapeB = shapeB;
  13127. beginShapeContactEvent.bodyA = shapeA.body;
  13128. beginShapeContactEvent.bodyB = shapeB.body;
  13129. this.dispatchEvent(beginShapeContactEvent);
  13130. }
  13131. beginShapeContactEvent.bodyA = beginShapeContactEvent.bodyB = beginShapeContactEvent.shapeA = beginShapeContactEvent.shapeB = null;
  13132. }
  13133. if(hasEndShapeContact){
  13134. for (var i = 0, l = removals.length; i < l; i += 2) {
  13135. var shapeA = this.getShapeById(removals[i]);
  13136. var shapeB = this.getShapeById(removals[i+1]);
  13137. endShapeContactEvent.shapeA = shapeA;
  13138. endShapeContactEvent.shapeB = shapeB;
  13139. endShapeContactEvent.bodyA = shapeA.body;
  13140. endShapeContactEvent.bodyB = shapeB.body;
  13141. this.dispatchEvent(endShapeContactEvent);
  13142. }
  13143. endShapeContactEvent.bodyA = endShapeContactEvent.bodyB = endShapeContactEvent.shapeA = endShapeContactEvent.shapeB = null;
  13144. }
  13145. };
  13146. })();
  13147. /**
  13148. * Sets all body forces in the world to zero.
  13149. * @method clearForces
  13150. */
  13151. World.prototype.clearForces = function(){
  13152. var bodies = this.bodies;
  13153. var N = bodies.length;
  13154. for(var i=0; i !== N; i++){
  13155. var b = bodies[i],
  13156. force = b.force,
  13157. tau = b.torque;
  13158. b.force.set(0,0,0);
  13159. b.torque.set(0,0,0);
  13160. }
  13161. };
  13162. },{"../collision/AABB":15,"../collision/ArrayCollisionMatrix":16,"../collision/NaiveBroadphase":19,"../collision/OverlapKeeper":21,"../collision/Ray":22,"../collision/RaycastResult":23,"../equations/ContactEquation":32,"../equations/FrictionEquation":34,"../material/ContactMaterial":37,"../material/Material":38,"../math/Quaternion":41,"../math/Vec3":43,"../objects/Body":44,"../shapes/Shape":56,"../solver/GSSolver":59,"../utils/EventTarget":62,"../utils/TupleDictionary":65,"./Narrowphase":68}],70:[function(require,module,exports){
  13163. var CANNON = require('cannon'),
  13164. quickhull = require('./lib/THREE.quickhull');
  13165. var PI_2 = Math.PI / 2;
  13166. var Type = {
  13167. BOX: 'Box',
  13168. CYLINDER: 'Cylinder',
  13169. SPHERE: 'Sphere',
  13170. HULL: 'ConvexPolyhedron',
  13171. MESH: 'Trimesh'
  13172. };
  13173. /**
  13174. * Given a THREE.Object3D instance, creates a corresponding CANNON shape.
  13175. * @param {THREE.Object3D} object
  13176. * @return {CANNON.Shape}
  13177. */
  13178. module.exports = CANNON.mesh2shape = function (object, options) {
  13179. options = options || {};
  13180. var geometry;
  13181. if (options.type === Type.BOX) {
  13182. return createBoundingBoxShape(object);
  13183. } else if (options.type === Type.CYLINDER) {
  13184. return createBoundingCylinderShape(object, options);
  13185. } else if (options.type === Type.SPHERE) {
  13186. return createBoundingSphereShape(object, options);
  13187. } else if (options.type === Type.HULL) {
  13188. return createConvexPolyhedron(object);
  13189. } else if (options.type === Type.MESH) {
  13190. geometry = getGeometry(object);
  13191. return geometry ? createTrimeshShape(geometry) : null;
  13192. } else if (options.type) {
  13193. throw new Error('[CANNON.mesh2shape] Invalid type "%s".', options.type);
  13194. }
  13195. geometry = getGeometry(object);
  13196. if (!geometry) return null;
  13197. var type = geometry.metadata
  13198. ? geometry.metadata.type
  13199. : geometry.type;
  13200. switch (type) {
  13201. case 'BoxGeometry':
  13202. case 'BoxBufferGeometry':
  13203. return createBoxShape(geometry);
  13204. case 'CylinderGeometry':
  13205. case 'CylinderBufferGeometry':
  13206. return createCylinderShape(geometry);
  13207. case 'PlaneGeometry':
  13208. case 'PlaneBufferGeometry':
  13209. return createPlaneShape(geometry);
  13210. case 'SphereGeometry':
  13211. case 'SphereBufferGeometry':
  13212. return createSphereShape(geometry);
  13213. case 'TubeGeometry':
  13214. case 'Geometry':
  13215. case 'BufferGeometry':
  13216. return createBoundingBoxShape(object);
  13217. default:
  13218. console.warn('Unrecognized geometry: "%s". Using bounding box as shape.', geometry.type);
  13219. return createBoxShape(geometry);
  13220. }
  13221. };
  13222. CANNON.mesh2shape.Type = Type;
  13223. /******************************************************************************
  13224. * Shape construction
  13225. */
  13226. /**
  13227. * @param {THREE.Geometry} geometry
  13228. * @return {CANNON.Shape}
  13229. */
  13230. function createBoxShape (geometry) {
  13231. var vertices = getVertices(geometry);
  13232. if (!vertices.length) return null;
  13233. geometry.computeBoundingBox();
  13234. var box = geometry.boundingBox;
  13235. return new CANNON.Box(new CANNON.Vec3(
  13236. (box.max.x - box.min.x) / 2,
  13237. (box.max.y - box.min.y) / 2,
  13238. (box.max.z - box.min.z) / 2
  13239. ));
  13240. }
  13241. /**
  13242. * Bounding box needs to be computed with the entire mesh, not just geometry.
  13243. * @param {THREE.Object3D} mesh
  13244. * @return {CANNON.Shape}
  13245. */
  13246. function createBoundingBoxShape (object) {
  13247. var shape, localPosition, worldPosition,
  13248. box = new THREE.Box3();
  13249. box.setFromObject(object);
  13250. if (!isFinite(box.min.lengthSq())) return null;
  13251. shape = new CANNON.Box(new CANNON.Vec3(
  13252. (box.max.x - box.min.x) / 2,
  13253. (box.max.y - box.min.y) / 2,
  13254. (box.max.z - box.min.z) / 2
  13255. ));
  13256. object.updateMatrixWorld();
  13257. worldPosition = new THREE.Vector3();
  13258. worldPosition.setFromMatrixPosition(object.matrixWorld);
  13259. localPosition = box.translate(worldPosition.negate()).getCenter();
  13260. if (localPosition.lengthSq()) {
  13261. shape.offset = localPosition;
  13262. }
  13263. return shape;
  13264. }
  13265. /**
  13266. * Computes 3D convex hull as a CANNON.ConvexPolyhedron.
  13267. * @param {THREE.Object3D} mesh
  13268. * @return {CANNON.Shape}
  13269. */
  13270. function createConvexPolyhedron (object) {
  13271. var i, vertices, faces, hull,
  13272. eps = 1e-4,
  13273. geometry = getGeometry(object);
  13274. if (!geometry || !geometry.vertices.length) return null;
  13275. // Perturb.
  13276. for (i = 0; i < geometry.vertices.length; i++) {
  13277. geometry.vertices[i].x += (Math.random() - 0.5) * eps;
  13278. geometry.vertices[i].y += (Math.random() - 0.5) * eps;
  13279. geometry.vertices[i].z += (Math.random() - 0.5) * eps;
  13280. }
  13281. // Compute the 3D convex hull.
  13282. hull = quickhull(geometry);
  13283. // Convert from THREE.Vector3 to CANNON.Vec3.
  13284. vertices = new Array(hull.vertices.length);
  13285. for (i = 0; i < hull.vertices.length; i++) {
  13286. vertices[i] = new CANNON.Vec3(hull.vertices[i].x, hull.vertices[i].y, hull.vertices[i].z);
  13287. }
  13288. // Convert from THREE.Face to Array<number>.
  13289. faces = new Array(hull.faces.length);
  13290. for (i = 0; i < hull.faces.length; i++) {
  13291. faces[i] = [hull.faces[i].a, hull.faces[i].b, hull.faces[i].c];
  13292. }
  13293. return new CANNON.ConvexPolyhedron(vertices, faces);
  13294. }
  13295. /**
  13296. * @param {THREE.Geometry} geometry
  13297. * @return {CANNON.Shape}
  13298. */
  13299. function createCylinderShape (geometry) {
  13300. var shape,
  13301. params = geometry.metadata
  13302. ? geometry.metadata.parameters
  13303. : geometry.parameters;
  13304. shape = new CANNON.Cylinder(
  13305. params.radiusTop,
  13306. params.radiusBottom,
  13307. params.height,
  13308. params.radialSegments
  13309. );
  13310. // Include metadata for serialization.
  13311. shape._type = CANNON.Shape.types.CYLINDER; // Patch schteppe/cannon.js#329.
  13312. shape.radiusTop = params.radiusTop;
  13313. shape.radiusBottom = params.radiusBottom;
  13314. shape.height = params.height;
  13315. shape.numSegments = params.radialSegments;
  13316. shape.orientation = new CANNON.Quaternion();
  13317. shape.orientation.setFromEuler(THREE.Math.degToRad(-90), 0, 0, 'XYZ').normalize();
  13318. return shape;
  13319. }
  13320. /**
  13321. * @param {THREE.Object3D} object
  13322. * @return {CANNON.Shape}
  13323. */
  13324. function createBoundingCylinderShape (object, options) {
  13325. var shape, height, radius,
  13326. box = new THREE.Box3(),
  13327. axes = ['x', 'y', 'z'],
  13328. majorAxis = options.cylinderAxis || 'y',
  13329. minorAxes = axes.splice(axes.indexOf(majorAxis), 1) && axes;
  13330. box.setFromObject(object);
  13331. if (!isFinite(box.min.lengthSq())) return null;
  13332. // Compute cylinder dimensions.
  13333. height = box.max[majorAxis] - box.min[majorAxis];
  13334. radius = 0.5 * Math.max(
  13335. box.max[minorAxes[0]] - box.min[minorAxes[0]],
  13336. box.max[minorAxes[1]] - box.min[minorAxes[1]]
  13337. );
  13338. // Create shape.
  13339. shape = new CANNON.Cylinder(radius, radius, height, 12);
  13340. // Include metadata for serialization.
  13341. shape._type = CANNON.Shape.types.CYLINDER; // Patch schteppe/cannon.js#329.
  13342. shape.radiusTop = radius;
  13343. shape.radiusBottom = radius;
  13344. shape.height = height;
  13345. shape.numSegments = 12;
  13346. shape.orientation = new CANNON.Quaternion();
  13347. shape.orientation.setFromEuler(
  13348. majorAxis === 'y' ? PI_2 : 0,
  13349. majorAxis === 'z' ? PI_2 : 0,
  13350. 0,
  13351. 'XYZ'
  13352. ).normalize();
  13353. return shape;
  13354. }
  13355. /**
  13356. * @param {THREE.Geometry} geometry
  13357. * @return {CANNON.Shape}
  13358. */
  13359. function createPlaneShape (geometry) {
  13360. geometry.computeBoundingBox();
  13361. var box = geometry.boundingBox;
  13362. return new CANNON.Box(new CANNON.Vec3(
  13363. (box.max.x - box.min.x) / 2 || 0.1,
  13364. (box.max.y - box.min.y) / 2 || 0.1,
  13365. (box.max.z - box.min.z) / 2 || 0.1
  13366. ));
  13367. }
  13368. /**
  13369. * @param {THREE.Geometry} geometry
  13370. * @return {CANNON.Shape}
  13371. */
  13372. function createSphereShape (geometry) {
  13373. var params = geometry.metadata
  13374. ? geometry.metadata.parameters
  13375. : geometry.parameters;
  13376. return new CANNON.Sphere(params.radius);
  13377. }
  13378. /**
  13379. * @param {THREE.Object3D} object
  13380. * @return {CANNON.Shape}
  13381. */
  13382. function createBoundingSphereShape (object, options) {
  13383. if (options.sphereRadius) {
  13384. return new CANNON.Sphere(options.sphereRadius);
  13385. }
  13386. var geometry = getGeometry(object);
  13387. if (!geometry) return null;
  13388. geometry.computeBoundingSphere();
  13389. return new CANNON.Sphere(geometry.boundingSphere.radius);
  13390. }
  13391. /**
  13392. * @param {THREE.Geometry} geometry
  13393. * @return {CANNON.Shape}
  13394. */
  13395. function createTrimeshShape (geometry) {
  13396. var indices,
  13397. vertices = getVertices(geometry);
  13398. if (!vertices.length) return null;
  13399. indices = Object.keys(vertices).map(Number);
  13400. return new CANNON.Trimesh(vertices, indices);
  13401. }
  13402. /******************************************************************************
  13403. * Utils
  13404. */
  13405. /**
  13406. * Returns a single geometry for the given object. If the object is compound,
  13407. * its geometries are automatically merged.
  13408. * @param {THREE.Object3D} object
  13409. * @return {THREE.Geometry}
  13410. */
  13411. function getGeometry (object) {
  13412. var matrix, mesh,
  13413. meshes = getMeshes(object),
  13414. tmp = new THREE.Geometry(),
  13415. combined = new THREE.Geometry();
  13416. if (meshes.length === 0) return null;
  13417. // Apply scale – it can't easily be applied to a CANNON.Shape later.
  13418. if (meshes.length === 1) {
  13419. var position = new THREE.Vector3(),
  13420. quaternion = new THREE.Quaternion(),
  13421. scale = new THREE.Vector3();
  13422. if (meshes[0].geometry.isBufferGeometry) {
  13423. if (meshes[0].geometry.attributes.position) {
  13424. tmp.fromBufferGeometry(meshes[0].geometry);
  13425. }
  13426. } else {
  13427. tmp = meshes[0].geometry.clone();
  13428. }
  13429. tmp.metadata = meshes[0].geometry.metadata;
  13430. meshes[0].updateMatrixWorld();
  13431. meshes[0].matrixWorld.decompose(position, quaternion, scale);
  13432. return tmp.scale(scale.x, scale.y, scale.z);
  13433. }
  13434. // Recursively merge geometry, preserving local transforms.
  13435. while ((mesh = meshes.pop())) {
  13436. mesh.updateMatrixWorld();
  13437. if (mesh.geometry.isBufferGeometry) {
  13438. tmp.fromBufferGeometry(mesh.geometry);
  13439. combined.merge(tmp, mesh.matrixWorld);
  13440. } else {
  13441. combined.merge(mesh.geometry, mesh.matrixWorld);
  13442. }
  13443. }
  13444. matrix = new THREE.Matrix4();
  13445. matrix.scale(object.scale);
  13446. combined.applyMatrix(matrix);
  13447. return combined;
  13448. }
  13449. /**
  13450. * @param {THREE.Geometry} geometry
  13451. * @return {Array<number>}
  13452. */
  13453. function getVertices (geometry) {
  13454. if (!geometry.attributes) {
  13455. geometry = new THREE.BufferGeometry().fromGeometry(geometry);
  13456. }
  13457. return (geometry.attributes.position || {}).array || [];
  13458. }
  13459. /**
  13460. * Returns a flat array of THREE.Mesh instances from the given object. If
  13461. * nested transformations are found, they are applied to child meshes
  13462. * as mesh.userData.matrix, so that each mesh has its position/rotation/scale
  13463. * independently of all of its parents except the top-level object.
  13464. * @param {THREE.Object3D} object
  13465. * @return {Array<THREE.Mesh>}
  13466. */
  13467. function getMeshes (object) {
  13468. var meshes = [];
  13469. object.traverse(function (o) {
  13470. if (o.type === 'Mesh') {
  13471. meshes.push(o);
  13472. }
  13473. });
  13474. return meshes;
  13475. }
  13476. },{"./lib/THREE.quickhull":71,"cannon":14}],71:[function(require,module,exports){
  13477. /**
  13478. QuickHull
  13479. ---------
  13480. The MIT License
  13481. Copyright &copy; 2010-2014 three.js authors
  13482. Permission is hereby granted, free of charge, to any person obtaining a copy
  13483. of this software and associated documentation files (the "Software"), to deal
  13484. in the Software without restriction, including without limitation the rights
  13485. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13486. copies of the Software, and to permit persons to whom the Software is
  13487. furnished to do so, subject to the following conditions:
  13488. The above copyright notice and this permission notice shall be included in
  13489. all copies or substantial portions of the Software.
  13490. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13491. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13492. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  13493. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  13494. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  13495. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  13496. THE SOFTWARE.
  13497. @author mark lundin / http://mark-lundin.com
  13498. This is a 3D implementation of the Quick Hull algorithm.
  13499. It is a fast way of computing a convex hull with average complexity
  13500. of O(n log(n)).
  13501. It uses depends on three.js and is supposed to create THREE.Geometry.
  13502. It's also very messy
  13503. */
  13504. module.exports = (function(){
  13505. var faces = [],
  13506. faceStack = [],
  13507. i, NUM_POINTS, extremes,
  13508. max = 0,
  13509. dcur, current, j, v0, v1, v2, v3,
  13510. N, D;
  13511. var ab, ac, ax,
  13512. suba, subb, normal,
  13513. diff, subaA, subaB, subC;
  13514. function reset(){
  13515. ab = new THREE.Vector3(),
  13516. ac = new THREE.Vector3(),
  13517. ax = new THREE.Vector3(),
  13518. suba = new THREE.Vector3(),
  13519. subb = new THREE.Vector3(),
  13520. normal = new THREE.Vector3(),
  13521. diff = new THREE.Vector3(),
  13522. subaA = new THREE.Vector3(),
  13523. subaB = new THREE.Vector3(),
  13524. subC = new THREE.Vector3();
  13525. }
  13526. //temporary vectors
  13527. function process( points ){
  13528. // Iterate through all the faces and remove
  13529. while( faceStack.length > 0 ){
  13530. cull( faceStack.shift(), points );
  13531. }
  13532. }
  13533. var norm = function(){
  13534. var ca = new THREE.Vector3(),
  13535. ba = new THREE.Vector3(),
  13536. N = new THREE.Vector3();
  13537. return function( a, b, c ){
  13538. ca.subVectors( c, a );
  13539. ba.subVectors( b, a );
  13540. N.crossVectors( ca, ba );
  13541. return N.normalize();
  13542. }
  13543. }();
  13544. function getNormal( face, points ){
  13545. if( face.normal !== undefined ) return face.normal;
  13546. var p0 = points[face[0]],
  13547. p1 = points[face[1]],
  13548. p2 = points[face[2]];
  13549. ab.subVectors( p1, p0 );
  13550. ac.subVectors( p2, p0 );
  13551. normal.crossVectors( ac, ab );
  13552. normal.normalize();
  13553. return face.normal = normal.clone();
  13554. }
  13555. function assignPoints( face, pointset, points ){
  13556. // ASSIGNING POINTS TO FACE
  13557. var p0 = points[face[0]],
  13558. dots = [], apex,
  13559. norm = getNormal( face, points );
  13560. // Sory all the points by there distance from the plane
  13561. pointset.sort( function( aItem, bItem ){
  13562. dots[aItem.x/3] = dots[aItem.x/3] !== undefined ? dots[aItem.x/3] : norm.dot( suba.subVectors( aItem, p0 ));
  13563. dots[bItem.x/3] = dots[bItem.x/3] !== undefined ? dots[bItem.x/3] : norm.dot( subb.subVectors( bItem, p0 ));
  13564. return dots[aItem.x/3] - dots[bItem.x/3] ;
  13565. });
  13566. //TODO :: Must be a faster way of finding and index in this array
  13567. var index = pointset.length;
  13568. if( index === 1 ) dots[pointset[0].x/3] = norm.dot( suba.subVectors( pointset[0], p0 ));
  13569. while( index-- > 0 && dots[pointset[index].x/3] > 0 )
  13570. var point;
  13571. if( index + 1 < pointset.length && dots[pointset[index+1].x/3] > 0 ){
  13572. face.visiblePoints = pointset.splice( index + 1 );
  13573. }
  13574. }
  13575. function cull( face, points ){
  13576. var i = faces.length,
  13577. dot, visibleFace, currentFace,
  13578. visibleFaces = [face];
  13579. var apex = points.indexOf( face.visiblePoints.pop() );
  13580. // Iterate through all other faces...
  13581. while( i-- > 0 ){
  13582. currentFace = faces[i];
  13583. if( currentFace !== face ){
  13584. // ...and check if they're pointing in the same direction
  13585. dot = getNormal( currentFace, points ).dot( diff.subVectors( points[apex], points[currentFace[0]] ));
  13586. if( dot > 0 ){
  13587. visibleFaces.push( currentFace );
  13588. }
  13589. }
  13590. }
  13591. var index, neighbouringIndex, vertex;
  13592. // Determine Perimeter - Creates a bounded horizon
  13593. // 1. Pick an edge A out of all possible edges
  13594. // 2. Check if A is shared by any other face. a->b === b->a
  13595. // 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 )
  13596. // 3. If not shared, then add to convex horizon set,
  13597. //pick an end point (N) of the current edge A and choose a new edge NA connected to A.
  13598. //Restart from 1.
  13599. // 4. If A is shared, it is not an horizon edge, therefore flag both faces that share this edge as candidates for culling
  13600. // 5. If candidate geometry is a degenrate triangle (ie. the tangent space normal cannot be computed) then remove that triangle from all further processing
  13601. var j = i = visibleFaces.length;
  13602. var isDistinct = false,
  13603. hasOneVisibleFace = i === 1,
  13604. cull = [],
  13605. perimeter = [],
  13606. edgeIndex = 0, compareFace, nextIndex,
  13607. a, b;
  13608. var allPoints = [];
  13609. var originFace = [visibleFaces[0][0], visibleFaces[0][1], visibleFaces[0][1], visibleFaces[0][2], visibleFaces[0][2], visibleFaces[0][0]];
  13610. if( visibleFaces.length === 1 ){
  13611. currentFace = visibleFaces[0];
  13612. perimeter = [currentFace[0], currentFace[1], currentFace[1], currentFace[2], currentFace[2], currentFace[0]];
  13613. // remove visible face from list of faces
  13614. if( faceStack.indexOf( currentFace ) > -1 ){
  13615. faceStack.splice( faceStack.indexOf( currentFace ), 1 );
  13616. }
  13617. if( currentFace.visiblePoints ) allPoints = allPoints.concat( currentFace.visiblePoints );
  13618. faces.splice( faces.indexOf( currentFace ), 1 );
  13619. }else{
  13620. while( i-- > 0 ){ // for each visible face
  13621. currentFace = visibleFaces[i];
  13622. // remove visible face from list of faces
  13623. if( faceStack.indexOf( currentFace ) > -1 ){
  13624. faceStack.splice( faceStack.indexOf( currentFace ), 1 );
  13625. }
  13626. if( currentFace.visiblePoints ) allPoints = allPoints.concat( currentFace.visiblePoints );
  13627. faces.splice( faces.indexOf( currentFace ), 1 );
  13628. var isSharedEdge;
  13629. cEdgeIndex = 0;
  13630. while( cEdgeIndex < 3 ){ // Iterate through it's edges
  13631. isSharedEdge = false;
  13632. j = visibleFaces.length;
  13633. a = currentFace[cEdgeIndex]
  13634. b = currentFace[(cEdgeIndex+1)%3];
  13635. while( j-- > 0 && !isSharedEdge ){ // find another visible faces
  13636. compareFace = visibleFaces[j];
  13637. edgeIndex = 0;
  13638. // isSharedEdge = compareFace == currentFace;
  13639. if( compareFace !== currentFace ){
  13640. while( edgeIndex < 3 && !isSharedEdge ){ //Check all it's indices
  13641. nextIndex = ( edgeIndex + 1 );
  13642. isSharedEdge = ( compareFace[edgeIndex] === a && compareFace[nextIndex%3] === b ) ||
  13643. ( compareFace[edgeIndex] === b && compareFace[nextIndex%3] === a );
  13644. edgeIndex++;
  13645. }
  13646. }
  13647. }
  13648. if( !isSharedEdge || hasOneVisibleFace ){
  13649. perimeter.push( a );
  13650. perimeter.push( b );
  13651. }
  13652. cEdgeIndex++;
  13653. }
  13654. }
  13655. }
  13656. // create new face for all pairs around edge
  13657. i = 0;
  13658. var l = perimeter.length/2;
  13659. var f;
  13660. while( i < l ){
  13661. f = [ perimeter[i*2+1], apex, perimeter[i*2] ];
  13662. assignPoints( f, allPoints, points );
  13663. faces.push( f )
  13664. if( f.visiblePoints !== undefined )faceStack.push( f );
  13665. i++;
  13666. }
  13667. }
  13668. var distSqPointSegment = function(){
  13669. var ab = new THREE.Vector3(),
  13670. ac = new THREE.Vector3(),
  13671. bc = new THREE.Vector3();
  13672. return function( a, b, c ){
  13673. ab.subVectors( b, a );
  13674. ac.subVectors( c, a );
  13675. bc.subVectors( c, b );
  13676. var e = ac.dot(ab);
  13677. if (e < 0.0) return ac.dot( ac );
  13678. var f = ab.dot( ab );
  13679. if (e >= f) return bc.dot( bc );
  13680. return ac.dot( ac ) - e * e / f;
  13681. }
  13682. }();
  13683. return function( geometry ){
  13684. reset();
  13685. points = geometry.vertices;
  13686. faces = [],
  13687. faceStack = [],
  13688. i = NUM_POINTS = points.length,
  13689. extremes = points.slice( 0, 6 ),
  13690. max = 0;
  13691. /*
  13692. * FIND EXTREMETIES
  13693. */
  13694. while( i-- > 0 ){
  13695. if( points[i].x < extremes[0].x ) extremes[0] = points[i];
  13696. if( points[i].x > extremes[1].x ) extremes[1] = points[i];
  13697. if( points[i].y < extremes[2].y ) extremes[2] = points[i];
  13698. if( points[i].y < extremes[3].y ) extremes[3] = points[i];
  13699. if( points[i].z < extremes[4].z ) extremes[4] = points[i];
  13700. if( points[i].z < extremes[5].z ) extremes[5] = points[i];
  13701. }
  13702. /*
  13703. * Find the longest line between the extremeties
  13704. */
  13705. j = i = 6;
  13706. while( i-- > 0 ){
  13707. j = i - 1;
  13708. while( j-- > 0 ){
  13709. if( max < (dcur = extremes[i].distanceToSquared( extremes[j] )) ){
  13710. max = dcur;
  13711. v0 = extremes[ i ];
  13712. v1 = extremes[ j ];
  13713. }
  13714. }
  13715. }
  13716. // 3. Find the most distant point to the line segment, this creates a plane
  13717. i = 6;
  13718. max = 0;
  13719. while( i-- > 0 ){
  13720. dcur = distSqPointSegment( v0, v1, extremes[i]);
  13721. if( max < dcur ){
  13722. max = dcur;
  13723. v2 = extremes[ i ];
  13724. }
  13725. }
  13726. // 4. Find the most distant point to the plane.
  13727. N = norm(v0, v1, v2);
  13728. D = N.dot( v0 );
  13729. max = 0;
  13730. i = NUM_POINTS;
  13731. while( i-- > 0 ){
  13732. dcur = Math.abs( points[i].dot( N ) - D );
  13733. if( max < dcur ){
  13734. max = dcur;
  13735. v3 = points[i];
  13736. }
  13737. }
  13738. var v0Index = points.indexOf( v0 ),
  13739. v1Index = points.indexOf( v1 ),
  13740. v2Index = points.indexOf( v2 ),
  13741. v3Index = points.indexOf( v3 );
  13742. // We now have a tetrahedron as the base geometry.
  13743. // Now we must subdivide the
  13744. var tetrahedron =[
  13745. [ v2Index, v1Index, v0Index ],
  13746. [ v1Index, v3Index, v0Index ],
  13747. [ v2Index, v3Index, v1Index ],
  13748. [ v0Index, v3Index, v2Index ],
  13749. ];
  13750. subaA.subVectors( v1, v0 ).normalize();
  13751. subaB.subVectors( v2, v0 ).normalize();
  13752. subC.subVectors ( v3, v0 ).normalize();
  13753. var sign = subC.dot( new THREE.Vector3().crossVectors( subaB, subaA ));
  13754. // Reverse the winding if negative sign
  13755. if( sign < 0 ){
  13756. tetrahedron[0].reverse();
  13757. tetrahedron[1].reverse();
  13758. tetrahedron[2].reverse();
  13759. tetrahedron[3].reverse();
  13760. }
  13761. //One for each face of the pyramid
  13762. var pointsCloned = points.slice();
  13763. pointsCloned.splice( pointsCloned.indexOf( v0 ), 1 );
  13764. pointsCloned.splice( pointsCloned.indexOf( v1 ), 1 );
  13765. pointsCloned.splice( pointsCloned.indexOf( v2 ), 1 );
  13766. pointsCloned.splice( pointsCloned.indexOf( v3 ), 1 );
  13767. var i = tetrahedron.length;
  13768. while( i-- > 0 ){
  13769. assignPoints( tetrahedron[i], pointsCloned, points );
  13770. if( tetrahedron[i].visiblePoints !== undefined ){
  13771. faceStack.push( tetrahedron[i] );
  13772. }
  13773. faces.push( tetrahedron[i] );
  13774. }
  13775. process( points );
  13776. // Assign to our geometry object
  13777. var ll = faces.length;
  13778. while( ll-- > 0 ){
  13779. geometry.faces[ll] = new THREE.Face3( faces[ll][2], faces[ll][1], faces[ll][0], faces[ll].normal )
  13780. }
  13781. geometry.normalsNeedUpdate = true;
  13782. return geometry;
  13783. }
  13784. }())
  13785. },{}],72:[function(require,module,exports){
  13786. module.exports = {
  13787. schema: {
  13788. offset: {default: {x: 0, y: 0, z: 0}, type: 'vec3'}
  13789. },
  13790. init: function () {
  13791. this.active = false;
  13792. this.targetEl = null;
  13793. this.fire = this.fire.bind(this);
  13794. this.offset = new THREE.Vector3();
  13795. },
  13796. update: function () {
  13797. this.offset.copy(this.data.offset);
  13798. },
  13799. play: function () { this.el.addEventListener('click', this.fire); },
  13800. pause: function () { this.el.removeEventListener('click', this.fire); },
  13801. remove: function () { this.pause(); },
  13802. fire: function () {
  13803. var targetEl = this.el.sceneEl.querySelector('[checkpoint-controls]');
  13804. if (!targetEl) {
  13805. throw new Error('No `checkpoint-controls` component found.');
  13806. }
  13807. targetEl.components['checkpoint-controls'].setCheckpoint(this.el);
  13808. },
  13809. getOffset: function () {
  13810. return this.offset.copy(this.data.offset);
  13811. }
  13812. };
  13813. },{}],73:[function(require,module,exports){
  13814. /**
  13815. * Specifies an envMap on an entity, without replacing any existing material
  13816. * properties.
  13817. */
  13818. module.exports = {
  13819. schema: {
  13820. path: {default: ''},
  13821. extension: {default: 'jpg'},
  13822. format: {default: 'RGBFormat'},
  13823. enableBackground: {default: false}
  13824. },
  13825. init: function () {
  13826. var data = this.data;
  13827. this.texture = new THREE.CubeTextureLoader().load([
  13828. data.path + 'posx.' + data.extension, data.path + 'negx.' + data.extension,
  13829. data.path + 'posy.' + data.extension, data.path + 'negy.' + data.extension,
  13830. data.path + 'posz.' + data.extension, data.path + 'negz.' + data.extension
  13831. ]);
  13832. this.texture.format = THREE[data.format];
  13833. if (data.enableBackground) {
  13834. this.el.sceneEl.object3D.background = this.texture;
  13835. }
  13836. this.applyEnvMap();
  13837. this.el.addEventListener('object3dset', this.applyEnvMap.bind(this));
  13838. },
  13839. applyEnvMap: function () {
  13840. var mesh = this.el.getObject3D('mesh');
  13841. var envMap = this.texture;
  13842. if (!mesh) return;
  13843. mesh.traverse(function (node) {
  13844. if (node.material && 'envMap' in node.material) {
  13845. node.material.envMap = envMap;
  13846. node.material.needsUpdate = true;
  13847. }
  13848. });
  13849. }
  13850. };
  13851. },{}],74:[function(require,module,exports){
  13852. /**
  13853. * Based on aframe/examples/showcase/tracked-controls.
  13854. *
  13855. * Handles events coming from the hand-controls.
  13856. * Determines if the entity is grabbed or released.
  13857. * Updates its position to move along the controller.
  13858. */
  13859. module.exports = {
  13860. init: function () {
  13861. this.GRABBED_STATE = 'grabbed';
  13862. this.grabbing = false;
  13863. this.hitEl = /** @type {AFRAME.Element} */ null;
  13864. this.physics = /** @type {AFRAME.System} */ this.el.sceneEl.systems.physics;
  13865. this.constraint = /** @type {CANNON.Constraint} */ null;
  13866. // Bind event handlers
  13867. this.onHit = this.onHit.bind(this);
  13868. this.onGripOpen = this.onGripOpen.bind(this);
  13869. this.onGripClose = this.onGripClose.bind(this);
  13870. },
  13871. play: function () {
  13872. var el = this.el;
  13873. el.addEventListener('hit', this.onHit);
  13874. el.addEventListener('gripdown', this.onGripClose);
  13875. el.addEventListener('gripup', this.onGripOpen);
  13876. el.addEventListener('trackpaddown', this.onGripClose);
  13877. el.addEventListener('trackpadup', this.onGripOpen);
  13878. el.addEventListener('triggerdown', this.onGripClose);
  13879. el.addEventListener('triggerup', this.onGripOpen);
  13880. },
  13881. pause: function () {
  13882. var el = this.el;
  13883. el.removeEventListener('hit', this.onHit);
  13884. el.removeEventListener('gripdown', this.onGripClose);
  13885. el.removeEventListener('gripup', this.onGripOpen);
  13886. el.removeEventListener('trackpaddown', this.onGripClose);
  13887. el.removeEventListener('trackpadup', this.onGripOpen);
  13888. el.removeEventListener('triggerdown', this.onGripClose);
  13889. el.removeEventListener('triggerup', this.onGripOpen);
  13890. },
  13891. onGripClose: function (evt) {
  13892. this.grabbing = true;
  13893. },
  13894. onGripOpen: function (evt) {
  13895. var hitEl = this.hitEl;
  13896. this.grabbing = false;
  13897. if (!hitEl) { return; }
  13898. hitEl.removeState(this.GRABBED_STATE);
  13899. this.hitEl = undefined;
  13900. this.physics.world.removeConstraint(this.constraint);
  13901. this.constraint = null;
  13902. },
  13903. onHit: function (evt) {
  13904. var hitEl = evt.detail.el;
  13905. // If the element is already grabbed (it could be grabbed by another controller).
  13906. // If the hand is not grabbing the element does not stick.
  13907. // If we're already grabbing something you can't grab again.
  13908. if (!hitEl || hitEl.is(this.GRABBED_STATE) || !this.grabbing || this.hitEl) { return; }
  13909. hitEl.addState(this.GRABBED_STATE);
  13910. this.hitEl = hitEl;
  13911. this.constraint = new CANNON.LockConstraint(this.el.body, hitEl.body);
  13912. this.physics.world.addConstraint(this.constraint);
  13913. }
  13914. };
  13915. },{}],75:[function(require,module,exports){
  13916. var physics = require('aframe-physics-system');
  13917. module.exports = {
  13918. 'checkpoint': require('./checkpoint'),
  13919. 'cube-env-map': require('./cube-env-map'),
  13920. 'grab': require('./grab'),
  13921. 'jump-ability': require('./jump-ability'),
  13922. 'kinematic-body': require('./kinematic-body'),
  13923. 'mesh-smooth': require('./mesh-smooth'),
  13924. 'sphere-collider': require('./sphere-collider'),
  13925. 'toggle-velocity': require('./toggle-velocity'),
  13926. registerAll: function (AFRAME) {
  13927. if (this._registered) return;
  13928. AFRAME = AFRAME || window.AFRAME;
  13929. physics.registerAll();
  13930. if (!AFRAME.components['checkpoint']) AFRAME.registerComponent('checkpoint', this['checkpoint']);
  13931. if (!AFRAME.components['cube-env-map']) AFRAME.registerComponent('cube-env-map', this['cube-env-map']);
  13932. if (!AFRAME.components['grab']) AFRAME.registerComponent('grab', this['grab']);
  13933. if (!AFRAME.components['jump-ability']) AFRAME.registerComponent('jump-ability', this['jump-ability']);
  13934. if (!AFRAME.components['kinematic-body']) AFRAME.registerComponent('kinematic-body', this['kinematic-body']);
  13935. if (!AFRAME.components['mesh-smooth']) AFRAME.registerComponent('mesh-smooth', this['mesh-smooth']);
  13936. if (!AFRAME.components['sphere-collider']) AFRAME.registerComponent('sphere-collider', this['sphere-collider']);
  13937. if (!AFRAME.components['toggle-velocity']) AFRAME.registerComponent('toggle-velocity', this['toggle-velocity']);
  13938. this._registered = true;
  13939. }
  13940. };
  13941. },{"./checkpoint":72,"./cube-env-map":73,"./grab":74,"./jump-ability":76,"./kinematic-body":77,"./mesh-smooth":78,"./sphere-collider":79,"./toggle-velocity":80,"aframe-physics-system":2}],76:[function(require,module,exports){
  13942. var ACCEL_G = -9.8, // m/s^2
  13943. EASING = -15; // m/s^2
  13944. /**
  13945. * Jump ability.
  13946. */
  13947. module.exports = {
  13948. dependencies: ['velocity'],
  13949. /* Schema
  13950. ——————————————————————————————————————————————*/
  13951. schema: {
  13952. on: { default: 'keydown:Space gamepadbuttondown:0' },
  13953. playerHeight: { default: 1.764 },
  13954. maxJumps: { default: 1 },
  13955. distance: { default: 5 },
  13956. soundJump: { default: '' },
  13957. soundLand: { default: '' },
  13958. debug: { default: false }
  13959. },
  13960. init: function () {
  13961. this.velocity = 0;
  13962. this.numJumps = 0;
  13963. var beginJump = this.beginJump.bind(this),
  13964. events = this.data.on.split(' ');
  13965. this.bindings = {};
  13966. for (var i = 0; i < events.length; i++) {
  13967. this.bindings[events[i]] = beginJump;
  13968. this.el.addEventListener(events[i], beginJump);
  13969. }
  13970. this.bindings.collide = this.onCollide.bind(this);
  13971. this.el.addEventListener('collide', this.bindings.collide);
  13972. },
  13973. remove: function () {
  13974. for (var event in this.bindings) {
  13975. if (this.bindings.hasOwnProperty(event)) {
  13976. this.el.removeEventListener(event, this.bindings[event]);
  13977. delete this.bindings[event];
  13978. }
  13979. }
  13980. this.el.removeEventListener('collide', this.bindings.collide);
  13981. delete this.bindings.collide;
  13982. },
  13983. beginJump: function () {
  13984. if (this.numJumps < this.data.maxJumps) {
  13985. var data = this.data,
  13986. initialVelocity = Math.sqrt(-2 * data.distance * (ACCEL_G + EASING)),
  13987. v = this.el.getAttribute('velocity');
  13988. this.el.setAttribute('velocity', {x: v.x, y: initialVelocity, z: v.z});
  13989. this.numJumps++;
  13990. }
  13991. },
  13992. onCollide: function () {
  13993. this.numJumps = 0;
  13994. }
  13995. };
  13996. },{}],77:[function(require,module,exports){
  13997. /**
  13998. * Kinematic body.
  13999. *
  14000. * Managed dynamic body, which moves but is not affected (directly) by the
  14001. * physics engine. This is not a true kinematic body, in the sense that we are
  14002. * letting the physics engine _compute_ collisions against it and selectively
  14003. * applying those collisions to the object. The physics engine does not decide
  14004. * the position/velocity/rotation of the element.
  14005. *
  14006. * Used for the camera object, because full physics simulation would create
  14007. * movement that feels unnatural to the player. Bipedal movement does not
  14008. * translate nicely to rigid body physics.
  14009. *
  14010. * See: http://www.learn-cocos2d.com/2013/08/physics-engine-platformer-terrible-idea/
  14011. * And: http://oxleygamedev.blogspot.com/2011/04/player-physics-part-2.html
  14012. */
  14013. var CANNON = window.CANNON;
  14014. var EPS = 0.000001;
  14015. module.exports = {
  14016. dependencies: ['velocity'],
  14017. /*******************************************************************
  14018. * Schema
  14019. */
  14020. schema: {
  14021. mass: { default: 5 },
  14022. radius: { default: 1.3 },
  14023. height: { default: 1.764 },
  14024. linearDamping: { default: 0.05 },
  14025. enableSlopes: { default: true }
  14026. },
  14027. /*******************************************************************
  14028. * Lifecycle
  14029. */
  14030. init: function () {
  14031. this.system = this.el.sceneEl.systems.physics;
  14032. this.system.addBehavior(this, this.system.Phase.SIMULATE);
  14033. var el = this.el,
  14034. data = this.data,
  14035. position = (new CANNON.Vec3()).copy(el.getAttribute('position'));
  14036. this.body = new CANNON.Body({
  14037. material: this.system.material,
  14038. position: position,
  14039. mass: data.mass,
  14040. linearDamping: data.linearDamping,
  14041. fixedRotation: true
  14042. });
  14043. this.body.addShape(
  14044. new CANNON.Sphere(data.radius),
  14045. new CANNON.Vec3(0, data.radius - data.height, 0)
  14046. );
  14047. this.body.el = this.el;
  14048. this.el.body = this.body;
  14049. this.system.addBody(this.body);
  14050. },
  14051. remove: function () {
  14052. this.system.removeBody(this.body);
  14053. this.system.removeBehavior(this, this.system.Phase.SIMULATE);
  14054. delete this.el.body;
  14055. },
  14056. /*******************************************************************
  14057. * Tick
  14058. */
  14059. /**
  14060. * Checks CANNON.World for collisions and attempts to apply them to the
  14061. * element automatically, in a player-friendly way.
  14062. *
  14063. * There's extra logic for horizontal surfaces here. The basic requirements:
  14064. * (1) Only apply gravity when not in contact with _any_ horizontal surface.
  14065. * (2) When moving, project the velocity against exactly one ground surface.
  14066. * If in contact with two ground surfaces (e.g. ground + ramp), choose
  14067. * the one that collides with current velocity, if any.
  14068. */
  14069. step: (function () {
  14070. var velocity = new THREE.Vector3(),
  14071. normalizedVelocity = new THREE.Vector3(),
  14072. currentSurfaceNormal = new THREE.Vector3(),
  14073. groundNormal = new THREE.Vector3();
  14074. return function (t, dt) {
  14075. if (!dt) return;
  14076. var body = this.body,
  14077. data = this.data,
  14078. didCollide = false,
  14079. height, groundHeight = -Infinity,
  14080. groundBody;
  14081. dt = Math.min(dt, this.system.data.maxInterval * 1000);
  14082. groundNormal.set(0, 0, 0);
  14083. velocity.copy(this.el.getAttribute('velocity'));
  14084. body.velocity.copy(velocity);
  14085. body.position.copy(this.el.getAttribute('position'));
  14086. for (var i = 0, contact; (contact = this.system.world.contacts[i]); i++) {
  14087. // 1. Find any collisions involving this element. Get the contact
  14088. // normal, and make sure it's oriented _out_ of the other object and
  14089. // enabled (body.collisionReponse is true for both bodies)
  14090. if (!contact.enabled) { continue; }
  14091. if (body.id === contact.bi.id) {
  14092. contact.ni.negate(currentSurfaceNormal);
  14093. } else if (body.id === contact.bj.id) {
  14094. currentSurfaceNormal.copy(contact.ni);
  14095. } else {
  14096. continue;
  14097. }
  14098. didCollide = body.velocity.dot(currentSurfaceNormal) < -EPS;
  14099. if (didCollide && currentSurfaceNormal.y <= 0.5) {
  14100. // 2. If current trajectory attempts to move _through_ another
  14101. // object, project the velocity against the collision plane to
  14102. // prevent passing through.
  14103. velocity = velocity.projectOnPlane(currentSurfaceNormal);
  14104. } else if (currentSurfaceNormal.y > 0.5) {
  14105. // 3. If in contact with something roughly horizontal (+/- 45º) then
  14106. // consider that the current ground. Only the highest qualifying
  14107. // ground is retained.
  14108. height = body.id === contact.bi.id
  14109. ? Math.abs(contact.rj.y + contact.bj.position.y)
  14110. : Math.abs(contact.ri.y + contact.bi.position.y);
  14111. if (height > groundHeight) {
  14112. groundHeight = height;
  14113. groundNormal.copy(currentSurfaceNormal);
  14114. groundBody = body.id === contact.bi.id ? contact.bj : contact.bi;
  14115. }
  14116. }
  14117. }
  14118. normalizedVelocity.copy(velocity).normalize();
  14119. if (groundBody && normalizedVelocity.y < 0.5) {
  14120. if (!data.enableSlopes) {
  14121. groundNormal.set(0, 1, 0);
  14122. } else if (groundNormal.y < 1 - EPS) {
  14123. groundNormal.copy(this.raycastToGround(groundBody, groundNormal));
  14124. }
  14125. // 4. Project trajectory onto the top-most ground object, unless
  14126. // trajectory is > 45º.
  14127. velocity = velocity.projectOnPlane(groundNormal);
  14128. } else {
  14129. // 5. If not in contact with anything horizontal, apply world gravity.
  14130. // TODO - Why is the 4x scalar necessary.
  14131. velocity.add(this.system.world.gravity.scale(dt * 4.0 / 1000));
  14132. }
  14133. // 6. If the ground surface has a velocity, apply it directly to current
  14134. // position, not velocity, to preserve relative velocity.
  14135. if (groundBody && groundBody.el && groundBody.el.components.velocity) {
  14136. var groundVelocity = groundBody.el.getAttribute('velocity');
  14137. body.position.copy({
  14138. x: body.position.x + groundVelocity.x * dt / 1000,
  14139. y: body.position.y + groundVelocity.y * dt / 1000,
  14140. z: body.position.z + groundVelocity.z * dt / 1000
  14141. });
  14142. this.el.setAttribute('position', body.position);
  14143. }
  14144. body.velocity.copy(velocity);
  14145. this.el.setAttribute('velocity', velocity);
  14146. };
  14147. }()),
  14148. /**
  14149. * When walking on complex surfaces (trimeshes, borders between two shapes),
  14150. * the collision normals returned for the player sphere can be very
  14151. * inconsistent. To address this, raycast straight down, find the collision
  14152. * normal, and return whichever normal is more vertical.
  14153. * @param {CANNON.Body} groundBody
  14154. * @param {CANNON.Vec3} groundNormal
  14155. * @return {CANNON.Vec3}
  14156. */
  14157. raycastToGround: function (groundBody, groundNormal) {
  14158. var ray,
  14159. hitNormal,
  14160. vFrom = this.body.position,
  14161. vTo = this.body.position.clone();
  14162. vTo.y -= this.data.height;
  14163. ray = new CANNON.Ray(vFrom, vTo);
  14164. ray._updateDirection(); // TODO - Report bug.
  14165. ray.intersectBody(groundBody);
  14166. if (!ray.hasHit) return groundNormal;
  14167. // Compare ABS, in case we're projecting against the inside of the face.
  14168. hitNormal = ray.result.hitNormalWorld;
  14169. return Math.abs(hitNormal.y) > Math.abs(groundNormal.y) ? hitNormal : groundNormal;
  14170. }
  14171. };
  14172. },{}],78:[function(require,module,exports){
  14173. /**
  14174. * Apply this component to models that looks "blocky", to have Three.js compute
  14175. * vertex normals on the fly for a "smoother" look.
  14176. */
  14177. module.exports = {
  14178. init: function () {
  14179. this.el.addEventListener('model-loaded', function (e) {
  14180. e.detail.model.traverse(function (node) {
  14181. if (node.isMesh) node.geometry.computeVertexNormals();
  14182. });
  14183. })
  14184. }
  14185. }
  14186. },{}],79:[function(require,module,exports){
  14187. /**
  14188. * Based on aframe/examples/showcase/tracked-controls.
  14189. *
  14190. * Implement bounding sphere collision detection for entities with a mesh.
  14191. * Sets the specified state on the intersected entities.
  14192. *
  14193. * @property {string} objects - Selector of the entities to test for collision.
  14194. * @property {string} state - State to set on collided entities.
  14195. *
  14196. */
  14197. module.exports = {
  14198. schema: {
  14199. objects: {default: ''},
  14200. state: {default: 'collided'},
  14201. radius: {default: 0.05},
  14202. watch: {default: true}
  14203. },
  14204. init: function () {
  14205. /** @type {MutationObserver} */
  14206. this.observer = null;
  14207. /** @type {Array<Element>} Elements to watch for collisions. */
  14208. this.els = [];
  14209. /** @type {Array<Element>} Elements currently in collision state. */
  14210. this.collisions = [];
  14211. this.handleHit = this.handleHit.bind(this);
  14212. this.handleHitEnd = this.handleHitEnd.bind(this);
  14213. },
  14214. remove: function () {
  14215. this.pause();
  14216. },
  14217. play: function () {
  14218. var sceneEl = this.el.sceneEl;
  14219. if (this.data.watch) {
  14220. this.observer = new MutationObserver(this.update.bind(this, null));
  14221. this.observer.observe(sceneEl, {childList: true, subtree: true});
  14222. }
  14223. },
  14224. pause: function () {
  14225. if (this.observer) {
  14226. this.observer.disconnect();
  14227. this.observer = null;
  14228. }
  14229. },
  14230. /**
  14231. * Update list of entities to test for collision.
  14232. */
  14233. update: function () {
  14234. var data = this.data;
  14235. var objectEls;
  14236. // Push entities into list of els to intersect.
  14237. if (data.objects) {
  14238. objectEls = this.el.sceneEl.querySelectorAll(data.objects);
  14239. } else {
  14240. // If objects not defined, intersect with everything.
  14241. objectEls = this.el.sceneEl.children;
  14242. }
  14243. // Convert from NodeList to Array
  14244. this.els = Array.prototype.slice.call(objectEls);
  14245. },
  14246. tick: (function () {
  14247. var position = new THREE.Vector3(),
  14248. meshPosition = new THREE.Vector3(),
  14249. meshScale = new THREE.Vector3(),
  14250. colliderScale = new THREE.Vector3(),
  14251. distanceMap = new Map();
  14252. return function () {
  14253. var el = this.el,
  14254. data = this.data,
  14255. mesh = el.getObject3D('mesh'),
  14256. colliderRadius,
  14257. collisions = [];
  14258. if (!mesh) { return; }
  14259. distanceMap.clear();
  14260. position.copy(el.object3D.getWorldPosition());
  14261. el.object3D.getWorldScale(colliderScale);
  14262. colliderRadius = data.radius * scaleFactor(colliderScale);
  14263. // Update collision list.
  14264. this.els.forEach(intersect);
  14265. // Emit events and add collision states, in order of distance.
  14266. collisions
  14267. .sort(function (a, b) {
  14268. return distanceMap.get(a) > distanceMap.get(b) ? 1 : -1;
  14269. })
  14270. .forEach(this.handleHit);
  14271. // Remove collision state from current element.
  14272. if (collisions.length === 0) { el.emit('hit', {el: null}); }
  14273. // Remove collision state from other elements.
  14274. this.collisions.filter(function (el) {
  14275. return !distanceMap.has(el);
  14276. }).forEach(this.handleHitEnd);
  14277. // Store new collisions
  14278. this.collisions = collisions;
  14279. // Bounding sphere collision detection
  14280. function intersect (el) {
  14281. var radius, mesh, distance, box, extent, size;
  14282. if (!el.isEntity) { return; }
  14283. mesh = el.getObject3D('mesh');
  14284. if (!mesh) { return; }
  14285. box = new THREE.Box3().setFromObject(mesh);
  14286. size = box.getSize();
  14287. extent = Math.max(size.x, size.y, size.z) / 2;
  14288. radius = Math.sqrt(2 * extent * extent);
  14289. box.getCenter(meshPosition);
  14290. if (!radius) { return; }
  14291. distance = position.distanceTo(meshPosition);
  14292. if (distance < radius + colliderRadius) {
  14293. collisions.push(el);
  14294. distanceMap.set(el, distance);
  14295. }
  14296. }
  14297. // use max of scale factors to maintain bounding sphere collision
  14298. function scaleFactor (scaleVec) {
  14299. return Math.max.apply(null, scaleVec.toArray());
  14300. }
  14301. };
  14302. })(),
  14303. handleHit: function (targetEl) {
  14304. targetEl.emit('hit');
  14305. targetEl.addState(this.data.state);
  14306. this.el.emit('hit', {el: targetEl});
  14307. },
  14308. handleHitEnd: function (targetEl) {
  14309. targetEl.emit('hitend');
  14310. targetEl.removeState(this.data.state);
  14311. this.el.emit('hitend', {el: targetEl});
  14312. }
  14313. };
  14314. },{}],80:[function(require,module,exports){
  14315. /**
  14316. * Toggle velocity.
  14317. *
  14318. * Moves an object back and forth along an axis, within a min/max extent.
  14319. */
  14320. module.exports = {
  14321. dependencies: ['velocity'],
  14322. schema: {
  14323. axis: { default: 'x', oneOf: ['x', 'y', 'z'] },
  14324. min: { default: 0 },
  14325. max: { default: 0 },
  14326. speed: { default: 1 }
  14327. },
  14328. init: function () {
  14329. var velocity = {x: 0, y: 0, z: 0};
  14330. velocity[this.data.axis] = this.data.speed;
  14331. this.el.setAttribute('velocity', velocity);
  14332. if (this.el.sceneEl.addBehavior) this.el.sceneEl.addBehavior(this);
  14333. },
  14334. remove: function () {},
  14335. update: function () { this.tick(); },
  14336. tick: function () {
  14337. var data = this.data,
  14338. velocity = this.el.getAttribute('velocity'),
  14339. position = this.el.getAttribute('position');
  14340. if (velocity[data.axis] > 0 && position[data.axis] > data.max) {
  14341. velocity[data.axis] = -data.speed;
  14342. this.el.setAttribute('velocity', velocity);
  14343. } else if (velocity[data.axis] < 0 && position[data.axis] < data.min) {
  14344. velocity[data.axis] = data.speed;
  14345. this.el.setAttribute('velocity', velocity);
  14346. }
  14347. },
  14348. };
  14349. },{}]},{},[1]);