cannon.js 214 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049
  1. /*
  2. * Copyright (c) 2012 cannon.js Authors
  3. *
  4. * Permission is hereby granted, free of charge, to any person
  5. * obtaining a copy of this software and associated documentation
  6. * files (the "Software"), to deal in the Software without
  7. * restriction, including without limitation the rights to use, copy,
  8. * modify, merge, publish, distribute, sublicense, and/or sell copies
  9. * of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be
  13. * included in all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. */
  23. (function () {
  24. /**
  25. * @page About
  26. * cannon.js is a lightweight 3D physics engine for web applications. For more information and source code, go to the Github repository [schteppe/cannon.js](https://github.com/schteppe/cannon.js).
  27. */
  28. /**
  29. * @library cannon.js
  30. * @version 0.4.3
  31. * @brief A lightweight 3D physics engine for the web
  32. */
  33. var CANNON = CANNON || {};
  34. // Maintain compatibility with older browsers
  35. if(!this.Int32Array){
  36. this.Int32Array=Array;
  37. this.Float32Array=Array;
  38. }
  39. /**
  40. * @class CANNON.Mat3
  41. * @brief A 3x3 matrix.
  42. * @param array elements Array of nine elements. Optional.
  43. * @author schteppe / http://github.com/schteppe
  44. */
  45. CANNON.Mat3 = function(elements){
  46. /**
  47. * @property Array elements
  48. * @memberof CANNON.Mat3
  49. * @brief A vector of length 9, containing all matrix elements
  50. * The values in the array are stored in the following order:
  51. * | 0 1 2 |
  52. * | 3 4 5 |
  53. * | 6 7 8 |
  54. *
  55. */
  56. if(elements){
  57. this.elements = elements;
  58. } else {
  59. this.elements = [0,0,0,0,0,0,0,0,0];
  60. }
  61. };
  62. /**
  63. * @method identity
  64. * @memberof CANNON.Mat3
  65. * @brief Sets the matrix to identity
  66. * @todo Should perhaps be renamed to setIdentity() to be more clear.
  67. * @todo Create another function that immediately creates an identity matrix eg. eye()
  68. */
  69. CANNON.Mat3.prototype.identity = function(){
  70. this.elements[0] = 1;
  71. this.elements[1] = 0;
  72. this.elements[2] = 0;
  73. this.elements[3] = 0;
  74. this.elements[4] = 1;
  75. this.elements[5] = 0;
  76. this.elements[6] = 0;
  77. this.elements[7] = 0;
  78. this.elements[8] = 1;
  79. };
  80. CANNON.Mat3.prototype.setZero = function(){
  81. var e = this.elements;
  82. e[0] = 0;
  83. e[1] = 0;
  84. e[2] = 0;
  85. e[3] = 0;
  86. e[4] = 0;
  87. e[5] = 0;
  88. e[6] = 0;
  89. e[7] = 0;
  90. e[8] = 0;
  91. };
  92. /**
  93. * @method setTrace
  94. * @memberof CANNON.Mat3
  95. * @brief Sets the matrix diagonal elements from a Vec3
  96. */
  97. CANNON.Mat3.prototype.setTrace = function(vec3){
  98. var e = this.elements;
  99. e[0] = vec3.x;
  100. e[4] = vec3.y;
  101. e[8] = vec3.z;
  102. };
  103. /**
  104. * @method vmult
  105. * @memberof CANNON.Mat3
  106. * @brief Matrix-Vector multiplication
  107. * @param CANNON.Vec3 v The vector to multiply with
  108. * @param CANNON.Vec3 target Optional, target to save the result in.
  109. */
  110. CANNON.Mat3.prototype.vmult = function(v,target){
  111. target = target || new CANNON.Vec3();
  112. var e = this.elements,
  113. x = v.x,
  114. y = v.y,
  115. z = v.z;
  116. target.x = e[0]*x + e[1]*y + e[2]*z;
  117. target.y = e[3]*x + e[4]*y + e[5]*z;
  118. target.z = e[6]*x + e[7]*y + e[8]*z;
  119. return target;
  120. };
  121. /**
  122. * @method smult
  123. * @memberof CANNON.Mat3
  124. * @brief Matrix-scalar multiplication
  125. * @param float s
  126. */
  127. CANNON.Mat3.prototype.smult = function(s){
  128. for(var i=0; i<this.elements.length; i++){
  129. this.elements[i] *= s;
  130. }
  131. };
  132. /**
  133. * @method mmult
  134. * @memberof CANNON.Mat3
  135. * @brief Matrix multiplication
  136. * @param CANNON.Mat3 m Matrix to multiply with from left side.
  137. * @return CANNON.Mat3 The result.
  138. */
  139. CANNON.Mat3.prototype.mmult = function(m){
  140. var r = new CANNON.Mat3();
  141. for(var i=0; i<3; i++){
  142. for(var j=0; j<3; j++){
  143. var sum = 0.0;
  144. for(var k=0; k<3; k++){
  145. sum += m.elements[i+k*3] * this.elements[k+j*3];
  146. }
  147. r.elements[i+j*3] = sum;
  148. }
  149. }
  150. return r;
  151. };
  152. /**
  153. * @method solve
  154. * @memberof CANNON.Mat3
  155. * @brief Solve Ax=b
  156. * @param CANNON.Vec3 b The right hand side
  157. * @param CANNON.Vec3 target Optional. Target vector to save in.
  158. * @return CANNON.Vec3 The solution x
  159. * @todo should reuse arrays
  160. */
  161. CANNON.Mat3.prototype.solve = function(b,target){
  162. target = target || new CANNON.Vec3();
  163. // Construct equations
  164. var nr = 3; // num rows
  165. var nc = 4; // num cols
  166. var eqns = [];
  167. for(var i=0; i<nr*nc; i++){
  168. eqns.push(0);
  169. }
  170. var i,j;
  171. for(i=0; i<3; i++){
  172. for(j=0; j<3; j++){
  173. eqns[i+nc*j] = this.elements[i+3*j];
  174. }
  175. }
  176. eqns[3+4*0] = b.x;
  177. eqns[3+4*1] = b.y;
  178. eqns[3+4*2] = b.z;
  179. // Compute right upper triangular version of the matrix - Gauss elimination
  180. var n = 3, k = n, np;
  181. var kp = 4; // num rows
  182. var p, els;
  183. do {
  184. i = k - n;
  185. if (eqns[i+nc*i] === 0) {
  186. // the pivot is null, swap lines
  187. for (j = i + 1; j < k; j++) {
  188. if (eqns[i+nc*j] !== 0) {
  189. np = kp;
  190. do { // do ligne( i ) = ligne( i ) + ligne( k )
  191. p = kp - np;
  192. eqns[p+nc*i] += eqns[p+nc*j];
  193. } while (--np);
  194. break;
  195. }
  196. }
  197. }
  198. if (eqns[i+nc*i] !== 0) {
  199. for (j = i + 1; j < k; j++) {
  200. var multiplier = eqns[i+nc*j] / eqns[i+nc*i];
  201. np = kp;
  202. do { // do ligne( k ) = ligne( k ) - multiplier * ligne( i )
  203. p = kp - np;
  204. eqns[p+nc*j] = p <= i ? 0 : eqns[p+nc*j] - eqns[p+nc*i] * multiplier ;
  205. } while (--np);
  206. }
  207. }
  208. } while (--n);
  209. // Get the solution
  210. target.z = eqns[2*nc+3] / eqns[2*nc+2];
  211. target.y = (eqns[1*nc+3] - eqns[1*nc+2]*target.z) / eqns[1*nc+1];
  212. target.x = (eqns[0*nc+3] - eqns[0*nc+2]*target.z - eqns[0*nc+1]*target.y) / eqns[0*nc+0];
  213. if(isNaN(target.x) || isNaN(target.y) || isNaN(target.z) || target.x===Infinity || target.y===Infinity || target.z===Infinity){
  214. throw "Could not solve equation! Got x=["+target.toString()+"], b=["+b.toString()+"], A=["+this.toString()+"]";
  215. }
  216. return target;
  217. };
  218. /**
  219. * @method e
  220. * @memberof CANNON.Mat3
  221. * @brief Get an element in the matrix by index. Index starts at 0, not 1!!!
  222. * @param int row
  223. * @param int column
  224. * @param float value Optional. If provided, the matrix element will be set to this value.
  225. * @return float
  226. */
  227. CANNON.Mat3.prototype.e = function( row , column ,value){
  228. if(value===undefined){
  229. return this.elements[column+3*row];
  230. } else {
  231. // Set value
  232. this.elements[column+3*row] = value;
  233. }
  234. };
  235. /**
  236. * @method copy
  237. * @memberof CANNON.Mat3
  238. * @brief Copy the matrix
  239. * @param CANNON.Mat3 target Optional. Target to save the copy in.
  240. * @return CANNON.Mat3
  241. */
  242. CANNON.Mat3.prototype.copy = function(target){
  243. target = target || new CANNON.Mat3();
  244. for(var i=0; i<this.elements.length; i++){
  245. target.elements[i] = this.elements[i];
  246. }
  247. return target;
  248. };
  249. /**
  250. * @method toString
  251. * @memberof CANNON.Mat3
  252. * @brief Returns a string representation of the matrix.
  253. * @return string
  254. */
  255. CANNON.Mat3.prototype.toString = function(){
  256. var r = "";
  257. var sep = ",";
  258. for(var i=0; i<9; i++){
  259. r += this.elements[i] + sep;
  260. }
  261. return r;
  262. };
  263. /**
  264. * @method reverse
  265. * @memberof CANNON.Mat3
  266. * @brief reverse the matrix
  267. * @param CANNON.Mat3 target Optional. Target matrix to save in.
  268. * @return CANNON.Mat3 The solution x
  269. */
  270. CANNON.Mat3.prototype.reverse = function(target){
  271. target = target || new CANNON.Mat3();
  272. // Construct equations
  273. var nr = 3; // num rows
  274. var nc = 6; // num cols
  275. var eqns = [];
  276. for(var i=0; i<nr*nc; i++){
  277. eqns.push(0);
  278. }
  279. var i,j;
  280. for(i=0; i<3; i++){
  281. for(j=0; j<3; j++){
  282. eqns[i+nc*j] = this.elements[i+3*j];
  283. }
  284. }
  285. eqns[3+6*0] = 1;
  286. eqns[3+6*1] = 0;
  287. eqns[3+6*2] = 0;
  288. eqns[4+6*0] = 0;
  289. eqns[4+6*1] = 1;
  290. eqns[4+6*2] = 0;
  291. eqns[5+6*0] = 0;
  292. eqns[5+6*1] = 0;
  293. eqns[5+6*2] = 1;
  294. // Compute right upper triangular version of the matrix - Gauss elimination
  295. var n = 3, k = n, np;
  296. var kp = nc; // num rows
  297. var p;
  298. do {
  299. i = k - n;
  300. if (eqns[i+nc*i] === 0) {
  301. // the pivot is null, swap lines
  302. for (j = i + 1; j < k; j++) {
  303. if (eqns[i+nc*j] !== 0) {
  304. np = kp;
  305. do { // do line( i ) = line( i ) + line( k )
  306. p = kp - np;
  307. eqns[p+nc*i] += eqns[p+nc*j];
  308. } while (--np);
  309. break;
  310. }
  311. }
  312. }
  313. if (eqns[i+nc*i] !== 0) {
  314. for (j = i + 1; j < k; j++) {
  315. var multiplier = eqns[i+nc*j] / eqns[i+nc*i];
  316. np = kp;
  317. do { // do line( k ) = line( k ) - multiplier * line( i )
  318. p = kp - np;
  319. eqns[p+nc*j] = p <= i ? 0 : eqns[p+nc*j] - eqns[p+nc*i] * multiplier ;
  320. } while (--np);
  321. }
  322. }
  323. } while (--n);
  324. // eliminate the upper left triangle of the matrix
  325. i = 2;
  326. do {
  327. j = i-1;
  328. do {
  329. var multiplier = eqns[i+nc*j] / eqns[i+nc*i];
  330. np = nc;
  331. do {
  332. p = nc - np;
  333. eqns[p+nc*j] = eqns[p+nc*j] - eqns[p+nc*i] * multiplier ;
  334. } while (--np);
  335. } while (j--);
  336. } while (--i);
  337. // operations on the diagonal
  338. i = 2;
  339. do {
  340. var multiplier = 1 / eqns[i+nc*i];
  341. np = nc;
  342. do {
  343. p = nc - np;
  344. eqns[p+nc*i] = eqns[p+nc*i] * multiplier ;
  345. } while (--np);
  346. } while (i--);
  347. i = 2;
  348. do {
  349. j = 2;
  350. do {
  351. p = eqns[nr+j+nc*i];
  352. if( isNaN( p ) || p ===Infinity ){
  353. throw "Could not reverse! A=["+this.toString()+"]";
  354. }
  355. target.e( i , j , p );
  356. } while (j--);
  357. } while (i--);
  358. return target;
  359. };
  360. /**
  361. * @class CANNON.Vec3
  362. * @brief 3-dimensional vector
  363. * @param float x
  364. * @param float y
  365. * @param float z
  366. * @author schteppe
  367. */
  368. var numVecs = 0;
  369. CANNON.Vec3 = function(x,y,z){
  370. /**
  371. * @property float x
  372. * @memberof CANNON.Vec3
  373. */
  374. this.x = x||0.0;
  375. /**
  376. * @property float y
  377. * @memberof CANNON.Vec3
  378. */
  379. this.y = y||0.0;
  380. /**
  381. * @property float z
  382. * @memberof CANNON.Vec3
  383. */
  384. this.z = z||0.0;
  385. /*
  386. numVecs++;
  387. if(numVecs > 180)
  388. console.log(numVecs+" created");
  389. */
  390. };
  391. /**
  392. * @method cross
  393. * @memberof CANNON.Vec3
  394. * @brief Vector cross product
  395. * @param CANNON.Vec3 v
  396. * @param CANNON.Vec3 target Optional. Target to save in.
  397. * @return CANNON.Vec3
  398. */
  399. CANNON.Vec3.prototype.cross = function(v,target){
  400. var vx=v.x, vy=v.y, vz=v.z, x=this.x, y=this.y, z=this.z;
  401. target = target || new CANNON.Vec3();
  402. target.x = (y * vz) - (z * vy);
  403. target.y = (z * vx) - (x * vz);
  404. target.z = (x * vy) - (y * vx);
  405. return target;
  406. };
  407. /**
  408. * @method set
  409. * @memberof CANNON.Vec3
  410. * @brief Set the vectors' 3 elements
  411. * @param float x
  412. * @param float y
  413. * @param float z
  414. * @return CANNON.Vec3
  415. */
  416. CANNON.Vec3.prototype.set = function(x,y,z){
  417. this.x = x;
  418. this.y = y;
  419. this.z = z;
  420. return this;
  421. };
  422. /**
  423. * @method vadd
  424. * @memberof CANNON.Vec3
  425. * @brief Vector addition
  426. * @param CANNON.Vec3 v
  427. * @param CANNON.Vec3 target Optional.
  428. * @return CANNON.Vec3
  429. */
  430. CANNON.Vec3.prototype.vadd = function(v,target){
  431. if(target){
  432. target.x = v.x + this.x;
  433. target.y = v.y + this.y;
  434. target.z = v.z + this.z;
  435. } else {
  436. return new CANNON.Vec3(this.x + v.x,
  437. this.y + v.y,
  438. this.z + v.z);
  439. }
  440. };
  441. /**
  442. * @method vsub
  443. * @memberof CANNON.Vec3
  444. * @brief Vector subtraction
  445. * @param CANNON.Vec3 v
  446. * @param CANNON.Vec3 target Optional. Target to save in.
  447. * @return CANNON.Vec3
  448. */
  449. CANNON.Vec3.prototype.vsub = function(v,target){
  450. if(target){
  451. target.x = this.x - v.x;
  452. target.y = this.y - v.y;
  453. target.z = this.z - v.z;
  454. } else {
  455. return new CANNON.Vec3(this.x-v.x,
  456. this.y-v.y,
  457. this.z-v.z);
  458. }
  459. };
  460. /**
  461. * @method crossmat
  462. * @memberof CANNON.Vec3
  463. * @brief Get the cross product matrix a_cross from a vector, such that a x b = a_cross * b = c
  464. * @see http://www8.cs.umu.se/kurser/TDBD24/VT06/lectures/Lecture6.pdf
  465. * @return CANNON.Mat3
  466. */
  467. CANNON.Vec3.prototype.crossmat = function(){
  468. return new CANNON.Mat3([ 0, -this.z, this.y,
  469. this.z, 0, -this.x,
  470. -this.y, this.x, 0]);
  471. };
  472. /**
  473. * @method normalize
  474. * @memberof CANNON.Vec3
  475. * @brief Normalize the vector. Note that this changes the values in the vector.
  476. * @return float Returns the norm of the vector
  477. */
  478. CANNON.Vec3.prototype.normalize = function(){
  479. var x=this.x, y=this.y, z=this.z;
  480. var n = Math.sqrt(x*x + y*y + z*z);
  481. if(n>0.0){
  482. var invN = 1/n;
  483. this.x *= invN;
  484. this.y *= invN;
  485. this.z *= invN;
  486. } else {
  487. // Make something up
  488. this.x = 0;
  489. this.y = 0;
  490. this.z = 0;
  491. }
  492. return n;
  493. };
  494. /**
  495. * @method unit
  496. * @memberof CANNON.Vec3
  497. * @brief Get the version of this vector that is of length 1.
  498. * @param CANNON.Vec3 target Optional target to save in
  499. * @return CANNON.Vec3 Returns the unit vector
  500. */
  501. CANNON.Vec3.prototype.unit = function(target){
  502. target = target || new CANNON.Vec3();
  503. var x=this.x, y=this.y, z=this.z;
  504. var ninv = Math.sqrt(x*x + y*y + z*z);
  505. if(ninv>0.0){
  506. ninv = 1.0/ninv;
  507. target.x = x * ninv;
  508. target.y = y * ninv;
  509. target.z = z * ninv;
  510. } else {
  511. target.x = 1;
  512. target.y = 0;
  513. target.z = 0;
  514. }
  515. return target;
  516. };
  517. /**
  518. * @method norm
  519. * @memberof CANNON.Vec3
  520. * @brief Get the 2-norm (length) of the vector
  521. * @return float
  522. */
  523. CANNON.Vec3.prototype.norm = function(){
  524. var x=this.x, y=this.y, z=this.z;
  525. return Math.sqrt(x*x + y*y + z*z);
  526. };
  527. /**
  528. * @method norm2
  529. * @memberof CANNON.Vec3
  530. * @brief Get the squared length of the vector
  531. * @return float
  532. */
  533. CANNON.Vec3.prototype.norm2 = function(){
  534. return this.dot(this);
  535. };
  536. CANNON.Vec3.prototype.distanceTo = function(p){
  537. var x=this.x, y=this.y, z=this.z;
  538. var px=p.x, py=p.y, pz=p.z;
  539. return Math.sqrt((px-x)*(px-x)+
  540. (py-y)*(py-y)+
  541. (pz-z)*(pz-z));
  542. };
  543. /**
  544. * @method mult
  545. * @memberof CANNON.Vec3
  546. * @brief Multiply the vector with a scalar
  547. * @param float scalar
  548. * @param CANNON.Vec3 target
  549. * @return CANNON.Vec3
  550. */
  551. CANNON.Vec3.prototype.mult = function(scalar,target){
  552. target = target || new CANNON.Vec3();
  553. var x = this.x,
  554. y = this.y,
  555. z = this.z;
  556. target.x = scalar * x;
  557. target.y = scalar * y;
  558. target.z = scalar * z;
  559. return target;
  560. };
  561. /**
  562. * @method dot
  563. * @memberof CANNON.Vec3
  564. * @brief Calculate dot product
  565. * @param CANNON.Vec3 v
  566. * @return float
  567. */
  568. CANNON.Vec3.prototype.dot = function(v){
  569. return this.x * v.x + this.y * v.y + this.z * v.z;
  570. };
  571. /**
  572. * @method isZero
  573. * @memberof CANNON.Vec3
  574. * @return bool
  575. */
  576. CANNON.Vec3.prototype.isZero = function(){
  577. return this.x===0 && this.y===0 && this.z===0;
  578. };
  579. /**
  580. * @method negate
  581. * @memberof CANNON.Vec3
  582. * @brief Make the vector point in the opposite direction.
  583. * @param CANNON.Vec3 target Optional target to save in
  584. * @return CANNON.Vec3
  585. */
  586. CANNON.Vec3.prototype.negate = function(target){
  587. target = target || new CANNON.Vec3();
  588. target.x = -this.x;
  589. target.y = -this.y;
  590. target.z = -this.z;
  591. return target;
  592. };
  593. /**
  594. * @method tangents
  595. * @memberof CANNON.Vec3
  596. * @brief Compute two artificial tangents to the vector
  597. * @param CANNON.Vec3 t1 Vector object to save the first tangent in
  598. * @param CANNON.Vec3 t2 Vector object to save the second tangent in
  599. */
  600. var Vec3_tangents_n = new CANNON.Vec3();
  601. var Vec3_tangents_randVec = new CANNON.Vec3();
  602. CANNON.Vec3.prototype.tangents = function(t1,t2){
  603. var norm = this.norm();
  604. if(norm>0.0){
  605. var n = Vec3_tangents_n;
  606. var inorm = 1/norm;
  607. n.set(this.x*inorm,this.y*inorm,this.z*inorm);
  608. var randVec = Vec3_tangents_randVec;
  609. if(Math.abs(n.x) < 0.9){
  610. randVec.set(1,0,0);
  611. n.cross(randVec,t1);
  612. } else {
  613. randVec.set(0,1,0);
  614. n.cross(randVec,t1);
  615. }
  616. n.cross(t1,t2);
  617. } else {
  618. // The normal length is zero, make something up
  619. t1.set(1,0,0).normalize();
  620. t2.set(0,1,0).normalize();
  621. }
  622. };
  623. /**
  624. * @method toString
  625. * @memberof CANNON.Vec3
  626. * @brief Converts to a more readable format
  627. * @return string
  628. */
  629. CANNON.Vec3.prototype.toString = function(){
  630. return this.x+","+this.y+","+this.z;
  631. };
  632. /**
  633. * @method copy
  634. * @memberof CANNON.Vec3
  635. * @brief Copy the vector.
  636. * @param CANNON.Vec3 target
  637. * @return CANNON.Vec3
  638. */
  639. CANNON.Vec3.prototype.copy = function(target){
  640. target = target || new CANNON.Vec3();
  641. target.x = this.x;
  642. target.y = this.y;
  643. target.z = this.z;
  644. return target;
  645. };
  646. /**
  647. * @method lerp
  648. * @memberof CANNON.Vec3
  649. * @brief Do a linear interpolation between two vectors
  650. * @param CANNON.Vec3 v
  651. * @param float 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.
  652. * @param CANNON.Vec3 target
  653. */
  654. CANNON.Vec3.prototype.lerp = function(v,t,target){
  655. var x=this.x, y=this.y, z=this.z;
  656. target.x = x + (v.x-x)*t;
  657. target.y = y + (v.y-y)*t;
  658. target.z = z + (v.z-z)*t;
  659. };
  660. /**
  661. * @method almostEquals
  662. * @memberof CANNON.Vec3
  663. * @brief Check if a vector equals is almost equal to another one.
  664. * @param CANNON.Vec3 v
  665. * @param float precision
  666. * @return bool
  667. */
  668. CANNON.Vec3.prototype.almostEquals = function(v,precision){
  669. if(precision===undefined){
  670. precision = 1e-6;
  671. }
  672. if( Math.abs(this.x-v.x)>precision ||
  673. Math.abs(this.y-v.y)>precision ||
  674. Math.abs(this.z-v.z)>precision){
  675. return false;
  676. }
  677. return true;
  678. };
  679. /**
  680. * @method almostZero
  681. * @brief Check if a vector is almost zero
  682. * @param float precision
  683. * @memberof CANNON.Vec3
  684. */
  685. CANNON.Vec3.prototype.almostZero = function(precision){
  686. if(precision===undefined){
  687. precision = 1e-6;
  688. }
  689. if( Math.abs(this.x)>precision ||
  690. Math.abs(this.y)>precision ||
  691. Math.abs(this.z)>precision){
  692. return false;
  693. }
  694. return true;
  695. };
  696. /**
  697. * @class CANNON.Quaternion
  698. * @brief A Quaternion describes a rotation in 3D space.
  699. * @description 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.
  700. * @param float x Multiplier of the imaginary basis vector i.
  701. * @param float y Multiplier of the imaginary basis vector j.
  702. * @param float z Multiplier of the imaginary basis vector k.
  703. * @param float w Multiplier of the real part.
  704. * @see http://en.wikipedia.org/wiki/Quaternion
  705. */
  706. CANNON.Quaternion = function(x,y,z,w){
  707. /**
  708. * @property float x
  709. * @memberof CANNON.Quaternion
  710. */
  711. this.x = x!==undefined ? x : 0;
  712. /**
  713. * @property float y
  714. * @memberof CANNON.Quaternion
  715. */
  716. this.y = y!==undefined ? y : 0;
  717. /**
  718. * @property float z
  719. * @memberof CANNON.Quaternion
  720. */
  721. this.z = z!==undefined ? z : 0;
  722. /**
  723. * @property float w
  724. * @memberof CANNON.Quaternion
  725. * @brief The multiplier of the real quaternion basis vector.
  726. */
  727. this.w = w!==undefined ? w : 1;
  728. };
  729. /**
  730. * @method set
  731. * @memberof CANNON.Quaternion
  732. * @brief Set the value of the quaternion.
  733. * @param float x
  734. * @param float y
  735. * @param float z
  736. * @param float w
  737. */
  738. CANNON.Quaternion.prototype.set = function(x,y,z,w){
  739. this.x = x;
  740. this.y = y;
  741. this.z = z;
  742. this.w = w;
  743. };
  744. /**
  745. * @method toString
  746. * @memberof CANNON.Quaternion
  747. * @brief Convert to a readable format
  748. * @return string
  749. */
  750. CANNON.Quaternion.prototype.toString = function(){
  751. return this.x+","+this.y+","+this.z+","+this.w;
  752. };
  753. /**
  754. * @method setFromAxisAngle
  755. * @memberof CANNON.Quaternion
  756. * @brief Set the quaternion components given an axis and an angle.
  757. * @param CANNON.Vec3 axis
  758. * @param float angle in radians
  759. */
  760. CANNON.Quaternion.prototype.setFromAxisAngle = function(axis,angle){
  761. var s = Math.sin(angle*0.5);
  762. this.x = axis.x * s;
  763. this.y = axis.y * s;
  764. this.z = axis.z * s;
  765. this.w = Math.cos(angle*0.5);
  766. };
  767. // saves axis to targetAxis and returns
  768. CANNON.Quaternion.prototype.toAxisAngle = function(targetAxis){
  769. targetAxis = targetAxis || new CANNON.Vec3();
  770. this.normalize(); // if w>1 acos and sqrt will produce errors, this cant happen if quaternion is normalised
  771. var angle = 2 * Math.acos(this.w);
  772. var s = Math.sqrt(1-this.w*this.w); // assuming quaternion normalised then w is less than 1, so term always positive.
  773. if (s < 0.001) { // test to avoid divide by zero, s is always positive due to sqrt
  774. // if s close to zero then direction of axis not important
  775. targetAxis.x = this.x; // if it is important that axis is normalised then replace with x=1; y=z=0;
  776. targetAxis.y = this.y;
  777. targetAxis.z = this.z;
  778. } else {
  779. targetAxis.x = this.x / s; // normalise axis
  780. targetAxis.y = this.y / s;
  781. targetAxis.z = this.z / s;
  782. }
  783. return [targetAxis,angle];
  784. };
  785. /**
  786. * @method setFromVectors
  787. * @memberof CANNON.Quaternion
  788. * @brief Set the quaternion value given two vectors. The resulting rotation will be the needed rotation to rotate u to v.
  789. * @param CANNON.Vec3 u
  790. * @param CANNON.Vec3 v
  791. */
  792. CANNON.Quaternion.prototype.setFromVectors = function(u,v){
  793. var a = u.cross(v);
  794. this.x = a.x;
  795. this.y = a.y;
  796. this.z = a.z;
  797. this.w = Math.sqrt(Math.pow(u.norm(),2) * Math.pow(v.norm(),2)) + u.dot(v);
  798. this.normalize();
  799. };
  800. /**
  801. * @method mult
  802. * @memberof CANNON.Quaternion
  803. * @brief Quaternion multiplication
  804. * @param CANNON.Quaternion q
  805. * @param CANNON.Quaternion target Optional.
  806. * @return CANNON.Quaternion
  807. */
  808. var Quaternion_mult_va = new CANNON.Vec3();
  809. var Quaternion_mult_vb = new CANNON.Vec3();
  810. var Quaternion_mult_vaxvb = new CANNON.Vec3();
  811. CANNON.Quaternion.prototype.mult = function(q,target){
  812. target = target || new CANNON.Quaternion();
  813. var w = this.w,
  814. va = Quaternion_mult_va,
  815. vb = Quaternion_mult_vb,
  816. vaxvb = Quaternion_mult_vaxvb;
  817. va.set(this.x,this.y,this.z);
  818. vb.set(q.x,q.y,q.z);
  819. target.w = w*q.w - va.dot(vb);
  820. va.cross(vb,vaxvb);
  821. target.x = w * vb.x + q.w*va.x + vaxvb.x;
  822. target.y = w * vb.y + q.w*va.y + vaxvb.y;
  823. target.z = w * vb.z + q.w*va.z + vaxvb.z;
  824. return target;
  825. };
  826. /**
  827. * @method inverse
  828. * @memberof CANNON.Quaternion
  829. * @brief Get the inverse quaternion rotation.
  830. * @param CANNON.Quaternion target
  831. * @return CANNON.Quaternion
  832. */
  833. CANNON.Quaternion.prototype.inverse = function(target){
  834. var x = this.x, y = this.y, z = this.z, w = this.w;
  835. target = target || new CANNON.Quaternion();
  836. this.conjugate(target);
  837. var inorm2 = 1/(x*x + y*y + z*z + w*w);
  838. target.x *= inorm2;
  839. target.y *= inorm2;
  840. target.z *= inorm2;
  841. target.w *= inorm2;
  842. return target;
  843. };
  844. /**
  845. * @method conjugate
  846. * @memberof CANNON.Quaternion
  847. * @brief Get the quaternion conjugate
  848. * @param CANNON.Quaternion target
  849. * @return CANNON.Quaternion
  850. */
  851. CANNON.Quaternion.prototype.conjugate = function(target){
  852. target = target || new CANNON.Quaternion();
  853. target.x = -this.x;
  854. target.y = -this.y;
  855. target.z = -this.z;
  856. target.w = this.w;
  857. return target;
  858. };
  859. /**
  860. * @method normalize
  861. * @memberof CANNON.Quaternion
  862. * @brief Normalize the quaternion. Note that this changes the values of the quaternion.
  863. */
  864. CANNON.Quaternion.prototype.normalize = function(){
  865. var l = Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w);
  866. if ( l === 0 ) {
  867. this.x = 0;
  868. this.y = 0;
  869. this.z = 0;
  870. this.w = 0;
  871. } else {
  872. l = 1 / l;
  873. this.x *= l;
  874. this.y *= l;
  875. this.z *= l;
  876. this.w *= l;
  877. }
  878. };
  879. /**
  880. * @method normalizeFast
  881. * @memberof CANNON.Quaternion
  882. * @brief Approximation of quaternion normalization. Works best when quat is already almost-normalized.
  883. * @see http://jsperf.com/fast-quaternion-normalization
  884. * @author unphased, https://github.com/unphased
  885. */
  886. CANNON.Quaternion.prototype.normalizeFast = function () {
  887. var f = (3.0-(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w))/2.0;
  888. if ( f === 0 ) {
  889. this.x = 0;
  890. this.y = 0;
  891. this.z = 0;
  892. this.w = 0;
  893. } else {
  894. this.x *= f;
  895. this.y *= f;
  896. this.z *= f;
  897. this.w *= f;
  898. }
  899. };
  900. /**
  901. * @method vmult
  902. * @memberof CANNON.Quaternion
  903. * @brief Multiply the quaternion by a vector
  904. * @param CANNON.Vec3 v
  905. * @param CANNON.Vec3 target Optional
  906. * @return CANNON.Vec3
  907. */
  908. CANNON.Quaternion.prototype.vmult = function(v,target){
  909. target = target || new CANNON.Vec3();
  910. if(this.w===0.0){
  911. target.x = v.x;
  912. target.y = v.y;
  913. target.z = v.z;
  914. } else {
  915. var x = v.x,
  916. y = v.y,
  917. z = v.z;
  918. var qx = this.x,
  919. qy = this.y,
  920. qz = this.z,
  921. qw = this.w;
  922. // q*v
  923. var ix = qw * x + qy * z - qz * y,
  924. iy = qw * y + qz * x - qx * z,
  925. iz = qw * z + qx * y - qy * x,
  926. iw = -qx * x - qy * y - qz * z;
  927. target.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
  928. target.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
  929. target.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
  930. }
  931. return target;
  932. };
  933. /**
  934. * @method copy
  935. * @memberof CANNON.Quaternion
  936. * @param CANNON.Quaternion target
  937. */
  938. CANNON.Quaternion.prototype.copy = function(target){
  939. target.x = this.x;
  940. target.y = this.y;
  941. target.z = this.z;
  942. target.w = this.w;
  943. };
  944. /**
  945. * @method toEuler
  946. * @memberof CANNON.Quaternion
  947. * @brief Convert the quaternion to euler angle representation. Order: YZX, as this page describes: http://www.euclideanspace.com/maths/standards/index.htm
  948. * @param CANNON.Vec3 target
  949. * @param string order Three-character string e.g. "YZX", which also is default.
  950. */
  951. CANNON.Quaternion.prototype.toEuler = function(target,order){
  952. order = order || "YZX";
  953. var heading, attitude, bank;
  954. var x = this.x, y = this.y, z = this.z, w = this.w;
  955. switch(order){
  956. case "YZX":
  957. var test = x*y + z*w;
  958. if (test > 0.499) { // singularity at north pole
  959. heading = 2 * Math.atan2(x,w);
  960. attitude = Math.PI/2;
  961. bank = 0;
  962. }
  963. if (test < -0.499) { // singularity at south pole
  964. heading = -2 * Math.atan2(x,w);
  965. attitude = - Math.PI/2;
  966. bank = 0;
  967. }
  968. if(isNaN(heading)){
  969. var sqx = x*x;
  970. var sqy = y*y;
  971. var sqz = z*z;
  972. heading = Math.atan2(2*y*w - 2*x*z , 1 - 2*sqy - 2*sqz); // Heading
  973. attitude = Math.asin(2*test); // attitude
  974. bank = Math.atan2(2*x*w - 2*y*z , 1 - 2*sqx - 2*sqz); // bank
  975. }
  976. break;
  977. default:
  978. throw new Error("Euler order "+order+" not supported yet.");
  979. }
  980. target.y = heading;
  981. target.z = attitude;
  982. target.x = bank;
  983. };
  984. /**
  985. * @class CANNON.EventTarget
  986. * @see https://github.com/mrdoob/eventtarget.js/
  987. */
  988. CANNON.EventTarget = function () {
  989. var listeners = {};
  990. this.addEventListener = function ( type, listener ) {
  991. if ( listeners[ type ] === undefined ) {
  992. listeners[ type ] = [];
  993. }
  994. if ( listeners[ type ].indexOf( listener ) === - 1 ) {
  995. listeners[ type ].push( listener );
  996. }
  997. };
  998. this.dispatchEvent = function ( event ) {
  999. for ( var listener in listeners[ event.type ] ) {
  1000. listeners[ event.type ][ listener ]( event );
  1001. }
  1002. };
  1003. this.removeEventListener = function ( type, listener ) {
  1004. var index = listeners[ type ].indexOf( listener );
  1005. if ( index !== - 1 ) {
  1006. listeners[ type ].splice( index, 1 );
  1007. }
  1008. };
  1009. };
  1010. /**
  1011. * @class CANNON.ObjectPool
  1012. * @brief For pooling objects that can be reused.
  1013. */
  1014. CANNON.ObjectPool = function(){
  1015. this.objects = [];
  1016. this.type = Object;
  1017. };
  1018. CANNON.ObjectPool.prototype.release = function(){
  1019. var Nargs = arguments.length;
  1020. for(var i=0; i!==Nargs; i++){
  1021. this.objects.push(arguments[i]);
  1022. }
  1023. };
  1024. CANNON.ObjectPool.prototype.get = function(){
  1025. if(this.objects.length===0){
  1026. return this.constructObject();
  1027. } else {
  1028. return this.objects.pop();
  1029. }
  1030. };
  1031. CANNON.ObjectPool.prototype.constructObject = function(){
  1032. throw new Error("constructObject() not implemented in this ObjectPool subclass yet!");
  1033. };
  1034. /**
  1035. * @class CANNON.Vec3Pool
  1036. */
  1037. CANNON.Vec3Pool = function(){
  1038. CANNON.ObjectPool.call(this);
  1039. this.type = CANNON.Vec3;
  1040. };
  1041. CANNON.Vec3Pool.prototype = new CANNON.ObjectPool();
  1042. CANNON.Vec3Pool.prototype.constructObject = function(){
  1043. return new CANNON.Vec3();
  1044. };
  1045. /**
  1046. * @class CANNON.Shape
  1047. * @author schteppe
  1048. * @brief Base class for shapes
  1049. * @todo Should have a mechanism for caching bounding sphere radius instead of calculating it each time
  1050. */
  1051. CANNON.Shape = function(){
  1052. /**
  1053. * @property int type
  1054. * @memberof CANNON.Shape
  1055. * @brief The type of this shape. Must be set to an int > 0 by subclasses.
  1056. * @see CANNON.Shape.types
  1057. */
  1058. this.type = 0;
  1059. this.aabbmin = new CANNON.Vec3();
  1060. this.aabbmax = new CANNON.Vec3();
  1061. this.boundingSphereRadius = 0;
  1062. this.boundingSphereRadiusNeedsUpdate = true;
  1063. };
  1064. CANNON.Shape.prototype.constructor = CANNON.Shape;
  1065. /**
  1066. * @method computeBoundingSphereRadius
  1067. * @memberof CANNON.Shape
  1068. * @brief Computes the bounding sphere radius. The result is stored in the property .boundingSphereRadius
  1069. * @return float
  1070. */
  1071. CANNON.Shape.prototype.computeBoundingSphereRadius = function(){
  1072. throw "computeBoundingSphereRadius() not implemented for shape type "+this.type;
  1073. };
  1074. /**
  1075. * @method getBoundingSphereRadius
  1076. * @memberof CANNON.Shape
  1077. * @brief Returns the bounding sphere radius. The result is stored in the property .boundingSphereRadius
  1078. * @return float
  1079. */
  1080. CANNON.Shape.prototype.getBoundingSphereRadius = function(){
  1081. if (this.boundingSphereRadiusNeedsUpdate) {
  1082. this.computeBoundingSphereRadius();
  1083. }
  1084. return this.boundingSphereRadius;
  1085. };
  1086. /**
  1087. * @method volume
  1088. * @memberof CANNON.Shape
  1089. * @brief Get the volume of this shape
  1090. * @return float
  1091. */
  1092. CANNON.Shape.prototype.volume = function(){
  1093. throw "volume() not implemented for shape type "+this.type;
  1094. };
  1095. /**
  1096. * @method calculateLocalInertia
  1097. * @memberof CANNON.Shape
  1098. * @brief Calculates the inertia in the local frame for this shape.
  1099. * @return CANNON.Vec3
  1100. * @see http://en.wikipedia.org/wiki/List_of_moments_of_inertia
  1101. */
  1102. CANNON.Shape.prototype.calculateLocalInertia = function(mass,target){
  1103. throw "calculateLocalInertia() not implemented for shape type "+this.type;
  1104. };
  1105. /**
  1106. * @method calculateTransformedInertia
  1107. * @memberof CANNON.Shape
  1108. * @brief Calculates inertia in a specified frame for this shape.
  1109. * @return CANNON.Vec3
  1110. */
  1111. var Shape_calculateTransformedInertia_localInertia = new CANNON.Vec3();
  1112. var Shape_calculateTransformedInertia_worldInertia = new CANNON.Vec3();
  1113. CANNON.Shape.prototype.calculateTransformedInertia = function(mass,quat,target){
  1114. target = target || new CANNON.Vec3();
  1115. // Compute inertia in the world frame
  1116. //quat.normalize();
  1117. var localInertia = Shape_calculateTransformedInertia_localInertia;
  1118. var worldInertia = Shape_calculateTransformedInertia_worldInertia;
  1119. this.calculateLocalInertia(mass,localInertia);
  1120. // @todo Is this rotation OK? Check!
  1121. quat.vmult(localInertia,worldInertia);
  1122. target.x = Math.abs(worldInertia.x);
  1123. target.y = Math.abs(worldInertia.y);
  1124. target.z = Math.abs(worldInertia.z);
  1125. return target;
  1126. };
  1127. // Calculates the local aabb and sets the result to .aabbmax and .aabbmin
  1128. CANNON.Shape.calculateLocalAABB = function(){
  1129. throw new Error(".calculateLocalAABB is not implemented for this Shape yet!");
  1130. };
  1131. /**
  1132. * @property Object types
  1133. * @memberof CANNON.Shape
  1134. * @brief The available shape types.
  1135. */
  1136. CANNON.Shape.types = {
  1137. SPHERE:1,
  1138. PLANE:2,
  1139. BOX:4,
  1140. COMPOUND:8,
  1141. CONVEXPOLYHEDRON:16
  1142. };
  1143. /**
  1144. * @class CANNON.Body
  1145. * @brief Base class for all body types.
  1146. * @param string type
  1147. * @extends CANNON.EventTarget
  1148. * @event collide The body object dispatches a "collide" event whenever it collides with another body. Event parameters are "with" (the body it collides with) and "contact" (the contact equation that is generated).
  1149. */
  1150. CANNON.Body = function(type){
  1151. CANNON.EventTarget.apply(this);
  1152. this.type = type;
  1153. /**
  1154. * @property CANNON.World world
  1155. * @memberof CANNON.Body
  1156. * @brief Reference to the world the body is living in
  1157. */
  1158. this.world = null;
  1159. /**
  1160. * @property function preStep
  1161. * @memberof CANNON.Body
  1162. * @brief Callback function that is used BEFORE stepping the system. Use it to apply forces, for example. Inside the function, "this" will refer to this CANNON.Body object.
  1163. * @todo dispatch an event from the World instead
  1164. */
  1165. this.preStep = null;
  1166. /**
  1167. * @property function postStep
  1168. * @memberof CANNON.Body
  1169. * @brief Callback function that is used AFTER stepping the system. Inside the function, "this" will refer to this CANNON.Body object.
  1170. * @todo dispatch an event from the World instead
  1171. */
  1172. this.postStep = null;
  1173. this.vlambda = new CANNON.Vec3();
  1174. this.collisionFilterGroup = 1;
  1175. this.collisionFilterMask = 1;
  1176. };
  1177. /*
  1178. * @brief 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.
  1179. */
  1180. CANNON.Body.DYNAMIC = 1;
  1181. /*
  1182. * @brief 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.
  1183. */
  1184. CANNON.Body.STATIC = 2;
  1185. /*
  1186. * 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.
  1187. */
  1188. CANNON.Body.KINEMATIC = 4;
  1189. /**
  1190. * @class CANNON.Particle
  1191. * @brief A body consisting of one point mass. Does not have orientation.
  1192. * @param float mass
  1193. * @param CANNON.Material material
  1194. */
  1195. CANNON.Particle = function(mass,material){
  1196. // Check input
  1197. if(typeof(mass)!=="number"){
  1198. throw new Error("Argument 1 (mass) must be a number.");
  1199. }
  1200. if(typeof(material)!=="undefined" && !(material instanceof(CANNON.Material))){
  1201. throw new Error("Argument 3 (material) must be an instance of CANNON.Material.");
  1202. }
  1203. CANNON.Body.call(this,"particle");
  1204. /**
  1205. * @property CANNON.Vec3 position
  1206. * @memberof CANNON.Particle
  1207. */
  1208. this.position = new CANNON.Vec3();
  1209. /**
  1210. * @property CANNON.Vec3 initPosition
  1211. * @memberof CANNON.Particle
  1212. * @brief Initial position of the body
  1213. */
  1214. this.initPosition = new CANNON.Vec3();
  1215. /**
  1216. * @property CANNON.Vec3 velocity
  1217. * @memberof CANNON.Particle
  1218. */
  1219. this.velocity = new CANNON.Vec3();
  1220. /**
  1221. * @property CANNON.Vec3 initVelocity
  1222. * @memberof CANNON.Particle
  1223. */
  1224. this.initVelocity = new CANNON.Vec3();
  1225. /**
  1226. * @property CANNON.Vec3 force
  1227. * @memberof CANNON.Particle
  1228. * @brief Linear force on the body
  1229. */
  1230. this.force = new CANNON.Vec3();
  1231. /**
  1232. * @property float mass
  1233. * @memberof CANNON.Particle
  1234. */
  1235. this.mass = mass;
  1236. /**
  1237. * @property float invMass
  1238. * @memberof CANNON.Particle
  1239. */
  1240. this.invMass = mass>0 ? 1.0/mass : 0;
  1241. /**
  1242. * @property CANNON.Material material
  1243. * @memberof CANNON.Particle
  1244. */
  1245. this.material = material;
  1246. /**
  1247. * @property float linearDamping
  1248. * @memberof CANNON.Particle
  1249. */
  1250. this.linearDamping = 0.01; // Perhaps default should be zero here?
  1251. /**
  1252. * @property int motionstate
  1253. * @memberof CANNON.Particle
  1254. * @brief One of the states CANNON.Body.DYNAMIC, CANNON.Body.STATIC and CANNON.Body.KINEMATIC
  1255. */
  1256. this.motionstate = (mass <= 0.0 ? CANNON.Body.STATIC : CANNON.Body.DYNAMIC);
  1257. /**
  1258. * @property bool allowSleep
  1259. * @memberof CANNON.Particle
  1260. * @brief If true, the body will automatically fall to sleep.
  1261. */
  1262. this.allowSleep = true;
  1263. // 0:awake, 1:sleepy, 2:sleeping
  1264. this.sleepState = 0;
  1265. /**
  1266. * @property float sleepSpeedLimit
  1267. * @memberof CANNON.Particle
  1268. * @brief If the speed (the norm of the velocity) is smaller than this value, the body is considered sleepy.
  1269. */
  1270. this.sleepSpeedLimit = 0.1;
  1271. /**
  1272. * @property float sleepTimeLimit
  1273. * @memberof CANNON.Particle
  1274. * @brief If the body has been sleepy for this sleepTimeLimit seconds, it is considered sleeping.
  1275. */
  1276. this.sleepTimeLimit = 1;
  1277. this.timeLastSleepy = 0;
  1278. };
  1279. CANNON.Particle.prototype = new CANNON.Body();
  1280. CANNON.Particle.prototype.constructor = CANNON.Particle;
  1281. /**
  1282. * @method isAwake
  1283. * @memberof CANNON.Particle
  1284. * @return bool
  1285. */
  1286. CANNON.Particle.prototype.isAwake = function(){
  1287. return this.sleepState === 0;
  1288. };
  1289. /**
  1290. * @method isSleepy
  1291. * @memberof CANNON.Particle
  1292. * @return bool
  1293. */
  1294. CANNON.Particle.prototype.isSleepy = function(){
  1295. return this.sleepState === 1;
  1296. };
  1297. /**
  1298. * @method isSleeping
  1299. * @memberof CANNON.Particle
  1300. * @return bool
  1301. */
  1302. CANNON.Particle.prototype.isSleeping = function(){
  1303. return this.sleepState === 2;
  1304. };
  1305. /**
  1306. * @method wakeUp
  1307. * @memberof CANNON.Particle
  1308. * @brief Wake the body up.
  1309. */
  1310. CANNON.Particle.prototype.wakeUp = function(){
  1311. var s = this.sleepState;
  1312. this.sleepState = 0;
  1313. if(s === 2){
  1314. this.dispatchEvent({type:"wakeup"});
  1315. }
  1316. };
  1317. /**
  1318. * @method sleep
  1319. * @memberof CANNON.Particle
  1320. * @brief Force body sleep
  1321. */
  1322. CANNON.Particle.prototype.sleep = function(){
  1323. this.sleepState = 2;
  1324. };
  1325. /**
  1326. * @method sleepTick
  1327. * @memberof CANNON.Particle
  1328. * @param float time The world time in seconds
  1329. * @brief Called every timestep to update internal sleep timer and change sleep state if needed.
  1330. */
  1331. CANNON.Particle.prototype.sleepTick = function(time){
  1332. if(this.allowSleep){
  1333. var sleepState = this.sleepState;
  1334. var speedSquared = this.velocity.norm2();
  1335. var speedLimitSquared = Math.pow(this.sleepSpeedLimit,2);
  1336. if(sleepState===0 && speedSquared < speedLimitSquared){
  1337. this.sleepState = 1; // Sleepy
  1338. this.timeLastSleepy = time;
  1339. this.dispatchEvent({type:"sleepy"});
  1340. } else if(sleepState===1 && speedSquared > speedLimitSquared){
  1341. this.wakeUp(); // Wake up
  1342. } else if(sleepState===1 && (time - this.timeLastSleepy ) > this.sleepTimeLimit){
  1343. this.sleepState = 2; // Sleeping
  1344. this.dispatchEvent({type:"sleep"});
  1345. }
  1346. }
  1347. };
  1348. /**
  1349. * @class CANNON.RigidBody
  1350. * @brief Rigid body base class
  1351. * @param float mass
  1352. * @param CANNON.Shape shape
  1353. * @param CANNON.Material material
  1354. */
  1355. CANNON.RigidBody = function(mass,shape,material){
  1356. // Check input
  1357. if(typeof(mass)!=="number"){
  1358. throw new Error("Argument 1 (mass) must be a number.");
  1359. }
  1360. if(typeof(material)!=="undefined" && !(material instanceof(CANNON.Material))){
  1361. throw new Error("Argument 3 (material) must be an instance of CANNON.Material.");
  1362. }
  1363. CANNON.Particle.call(this,mass,material);
  1364. var that = this;
  1365. /**
  1366. * @property CANNON.Vec3 tau
  1367. * @memberof CANNON.RigidBody
  1368. * @brief Rotational force on the body, around center of mass
  1369. */
  1370. this.tau = new CANNON.Vec3();
  1371. /**
  1372. * @property CANNON.Quaternion quaternion
  1373. * @memberof CANNON.RigidBody
  1374. * @brief Orientation of the body
  1375. */
  1376. this.quaternion = new CANNON.Quaternion();
  1377. /**
  1378. * @property CANNON.Quaternion initQuaternion
  1379. * @memberof CANNON.RigidBody
  1380. */
  1381. this.initQuaternion = new CANNON.Quaternion();
  1382. /**
  1383. * @property CANNON.Vec3 angularVelocity
  1384. * @memberof CANNON.RigidBody
  1385. */
  1386. this.angularVelocity = new CANNON.Vec3();
  1387. /**
  1388. * @property CANNON.Vec3 initAngularVelocity
  1389. * @memberof CANNON.RigidBody
  1390. */
  1391. this.initAngularVelocity = new CANNON.Vec3();
  1392. /**
  1393. * @property CANNON.Shape shape
  1394. * @memberof CANNON.RigidBody
  1395. */
  1396. this.shape = shape;
  1397. /**
  1398. * @property CANNON.Vec3 inertia
  1399. * @memberof CANNON.RigidBody
  1400. */
  1401. this.inertia = new CANNON.Vec3();
  1402. shape.calculateLocalInertia(mass,this.inertia);
  1403. this.inertiaWorld = new CANNON.Vec3();
  1404. this.inertia.copy(this.inertiaWorld);
  1405. this.inertiaWorldAutoUpdate = false;
  1406. /**
  1407. * @property CANNON.Vec3 intInertia
  1408. * @memberof CANNON.RigidBody
  1409. */
  1410. this.invInertia = new CANNON.Vec3(this.inertia.x>0 ? 1.0/this.inertia.x : 0,
  1411. this.inertia.y>0 ? 1.0/this.inertia.y : 0,
  1412. this.inertia.z>0 ? 1.0/this.inertia.z : 0);
  1413. this.invInertiaWorld = new CANNON.Vec3();
  1414. this.invInertia.copy(this.invInertiaWorld);
  1415. this.invInertiaWorldAutoUpdate = false;
  1416. /**
  1417. * @property float angularDamping
  1418. * @memberof CANNON.RigidBody
  1419. */
  1420. this.angularDamping = 0.01; // Perhaps default should be zero here?
  1421. /**
  1422. * @property CANNON.Vec3 aabbmin
  1423. * @memberof CANNON.RigidBody
  1424. */
  1425. this.aabbmin = new CANNON.Vec3();
  1426. /**
  1427. * @property CANNON.Vec3 aabbmax
  1428. * @memberof CANNON.RigidBody
  1429. */
  1430. this.aabbmax = new CANNON.Vec3();
  1431. /**
  1432. * @property bool aabbNeedsUpdate
  1433. * @memberof CANNON.RigidBody
  1434. * @brief Indicates if the AABB needs to be updated before use.
  1435. */
  1436. this.aabbNeedsUpdate = true;
  1437. this.wlambda = new CANNON.Vec3();
  1438. };
  1439. CANNON.RigidBody.prototype = new CANNON.Particle(0);
  1440. CANNON.RigidBody.prototype.constructor = CANNON.RigidBody;
  1441. CANNON.RigidBody.prototype.computeAABB = function(){
  1442. this.shape.calculateWorldAABB(this.position,
  1443. this.quaternion,
  1444. this.aabbmin,
  1445. this.aabbmax);
  1446. this.aabbNeedsUpdate = false;
  1447. };
  1448. /**
  1449. * Apply force to a world point. This could for example be a point on the RigidBody surface. Applying force this way will add to Body.force and Body.tau.
  1450. * @param CANNON.Vec3 force The amount of force to add.
  1451. * @param CANNON.Vec3 worldPoint A world point to apply the force on.
  1452. */
  1453. var RigidBody_applyForce_r = new CANNON.Vec3();
  1454. var RigidBody_applyForce_rotForce = new CANNON.Vec3();
  1455. CANNON.RigidBody.prototype.applyForce = function(force,worldPoint){
  1456. // Compute point position relative to the body center
  1457. var r = RigidBody_applyForce_r;
  1458. worldPoint.vsub(this.position,r);
  1459. // Compute produced rotational force
  1460. var rotForce = RigidBody_applyForce_rotForce;
  1461. r.cross(force,rotForce);
  1462. // Add linear force
  1463. this.force.vadd(force,this.force);
  1464. // Add rotational force
  1465. this.tau.vadd(rotForce,this.tau);
  1466. };
  1467. /**
  1468. * Apply impulse to a world point. This could for example be a point on the RigidBody 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.
  1469. * @param CANNON.Vec3 impulse The amount of impulse to add.
  1470. * @param CANNON.Vec3 worldPoint A world point to apply the force on.
  1471. */
  1472. var RigidBody_applyImpulse_r = new CANNON.Vec3();
  1473. var RigidBody_applyImpulse_velo = new CANNON.Vec3();
  1474. var RigidBody_applyImpulse_rotVelo = new CANNON.Vec3();
  1475. CANNON.RigidBody.prototype.applyImpulse = function(impulse,worldPoint){
  1476. // Compute point position relative to the body center
  1477. var r = RigidBody_applyImpulse_r;
  1478. worldPoint.vsub(this.position,r);
  1479. // Compute produced central impulse velocity
  1480. var velo = RigidBody_applyImpulse_velo;
  1481. impulse.copy(velo);
  1482. velo.mult(this.invMass,velo);
  1483. // Add linear impulse
  1484. this.velocity.vadd(velo, this.velocity);
  1485. // Compute produced rotational impulse velocity
  1486. var rotVelo = RigidBody_applyImpulse_rotVelo;
  1487. r.cross(impulse,rotVelo);
  1488. rotVelo.x *= this.invInertia.x;
  1489. rotVelo.y *= this.invInertia.y;
  1490. rotVelo.z *= this.invInertia.z;
  1491. // Add rotational Impulse
  1492. this.angularVelocity.vadd(rotVelo, this.angularVelocity);
  1493. };
  1494. /**
  1495. * @brief Spherical rigid body
  1496. * @class CANNON.Sphere
  1497. * @extends CANNON.Shape
  1498. * @param float radius
  1499. * @author schteppe / http://github.com/schteppe
  1500. */
  1501. CANNON.Sphere = function(radius){
  1502. CANNON.Shape.call(this);
  1503. /**
  1504. * @property float radius
  1505. * @memberof CANNON.Sphere
  1506. */
  1507. this.radius = radius!==undefined ? Number(radius) : 1.0;
  1508. this.type = CANNON.Shape.types.SPHERE;
  1509. };
  1510. CANNON.Sphere.prototype = new CANNON.Shape();
  1511. CANNON.Sphere.prototype.constructor = CANNON.Sphere;
  1512. CANNON.Sphere.prototype.calculateLocalInertia = function(mass,target){
  1513. target = target || new CANNON.Vec3();
  1514. var I = 2.0*mass*this.radius*this.radius/5.0;
  1515. target.x = I;
  1516. target.y = I;
  1517. target.z = I;
  1518. return target;
  1519. };
  1520. CANNON.Sphere.prototype.volume = function(){
  1521. return 4.0 * Math.PI * this.radius / 3.0;
  1522. };
  1523. CANNON.Sphere.prototype.computeBoundingSphereRadius = function(){
  1524. this.boundingSphereRadiusNeedsUpdate = false;
  1525. this.boundingSphereRadius = this.radius;
  1526. };
  1527. CANNON.Sphere.prototype.calculateWorldAABB = function(pos,quat,min,max){
  1528. var r = this.radius;
  1529. var axes = ['x','y','z'];
  1530. for(var i=0; i<axes.length; i++){
  1531. var ax = axes[i];
  1532. min[ax] = pos[ax] - r;
  1533. max[ax] = pos[ax] + r;
  1534. }
  1535. };
  1536. /**
  1537. * @class CANNON.SPHSystem
  1538. * @brief Smoothed-particle hydrodynamics system
  1539. */
  1540. CANNON.SPHSystem = function(){
  1541. this.particles = [];
  1542. this.density = 1; // kg/m3
  1543. this.smoothingRadius = 1; // Adjust so there are about 15-20 neighbor particles within this radius
  1544. this.speedOfSound = 1;
  1545. this.viscosity = 0.01;
  1546. this.eps = 0.000001;
  1547. // Stuff Computed per particle
  1548. this.pressures = [];
  1549. this.densities = [];
  1550. this.neighbors = [];
  1551. }
  1552. CANNON.SPHSystem.prototype.add = function(particle){
  1553. this.particles.push(particle);
  1554. if(this.neighbors.length < this.particles.length)
  1555. this.neighbors.push([]);
  1556. };
  1557. CANNON.SPHSystem.prototype.remove = function(particle){
  1558. var idx = this.particles.indexOf(particle);
  1559. if(idx !== -1){
  1560. this.particles.splice(idx,1);
  1561. if(this.neighbors.length > this.particles.length)
  1562. this.neighbors.pop();
  1563. }
  1564. };
  1565. /**
  1566. * Get neighbors within smoothing volume, save in the array neighbors
  1567. * @param CANNON.Body particle
  1568. * @param Array neighbors
  1569. */
  1570. var SPHSystem_getNeighbors_dist = new CANNON.Vec3();
  1571. CANNON.SPHSystem.prototype.getNeighbors = function(particle,neighbors){
  1572. var N = this.particles.length,
  1573. id = particle.id,
  1574. R2 = this.smoothingRadius * this.smoothingRadius,
  1575. dist = SPHSystem_getNeighbors_dist;
  1576. for(var i=0; i!==N; i++){
  1577. var p = this.particles[i];
  1578. p.position.vsub(particle.position,dist);
  1579. if(id!==p.id && dist.norm2() < R2){
  1580. neighbors.push(p);
  1581. }
  1582. }
  1583. };
  1584. // Temp vectors for calculation
  1585. var SPHSystem_update_dist = new CANNON.Vec3(),
  1586. SPHSystem_update_a_pressure = new CANNON.Vec3(),
  1587. SPHSystem_update_a_visc = new CANNON.Vec3(),
  1588. SPHSystem_update_gradW = new CANNON.Vec3(),
  1589. SPHSystem_update_r_vec = new CANNON.Vec3(),
  1590. SPHSystem_update_u = new CANNON.Vec3(); // Relative velocity
  1591. CANNON.SPHSystem.prototype.update = function(){
  1592. var N = this.particles.length,
  1593. dist = SPHSystem_update_dist,
  1594. cs = this.speedOfSound,
  1595. eps = this.eps;
  1596. for(var i=0; i!==N; i++){
  1597. var p = this.particles[i]; // Current particle
  1598. var neighbors = this.neighbors[i];
  1599. // Get neighbors
  1600. neighbors.length = 0;
  1601. this.getNeighbors(p,neighbors);
  1602. neighbors.push(this.particles[i]); // Add current too
  1603. var numNeighbors = neighbors.length;
  1604. // Accumulate density for the particle
  1605. var sum = 0.0;
  1606. for(var j=0; j!==numNeighbors; j++){
  1607. //printf("Current particle has position %f %f %f\n",objects[id].pos.x(),objects[id].pos.y(),objects[id].pos.z());
  1608. p.position.vsub(neighbors[j].position, dist);
  1609. var len = dist.norm();
  1610. var weight = this.w(len);
  1611. sum += neighbors[j].mass * weight;
  1612. }
  1613. // Save
  1614. this.densities[i] = sum;
  1615. this.pressures[i] = cs * cs * (this.densities[i] - this.density);
  1616. }
  1617. // Add forces
  1618. // Sum to these accelerations
  1619. var a_pressure= SPHSystem_update_a_pressure;
  1620. var a_visc = SPHSystem_update_a_visc;
  1621. var gradW = SPHSystem_update_gradW;
  1622. var r_vec = SPHSystem_update_r_vec;
  1623. var u = SPHSystem_update_u;
  1624. for(var i=0; i!==N; i++){
  1625. var particle = this.particles[i];
  1626. a_pressure.set(0,0,0);
  1627. a_visc.set(0,0,0);
  1628. // Init vars
  1629. var Pij;
  1630. var nabla;
  1631. var Vij;
  1632. // Sum up for all other neighbors
  1633. var neighbors = this.neighbors[i];
  1634. var numNeighbors = neighbors.length;
  1635. //printf("Neighbors: ");
  1636. for(var j=0; j!==numNeighbors; j++){
  1637. var neighbor = neighbors[j];
  1638. //printf("%d ",nj);
  1639. // Get r once for all..
  1640. particle.position.vsub(neighbor.position,r_vec);
  1641. var r = r_vec.norm();
  1642. // Pressure contribution
  1643. Pij = -neighbor.mass * (this.pressures[i] / (this.densities[i]*this.densities[i] + eps) + this.pressures[j] / (this.densities[j]*this.densities[j] + eps));
  1644. this.gradw(r_vec, gradW);
  1645. // Add to pressure acceleration
  1646. gradW.mult(Pij , gradW)
  1647. a_pressure.vadd(gradW, a_pressure);
  1648. // Viscosity contribution
  1649. neighbor.velocity.vsub(particle.velocity, u);
  1650. u.mult( 1.0 / (0.0001+this.densities[i] * this.densities[j]) * this.viscosity * neighbor.mass , u );
  1651. nabla = this.nablaw(r);
  1652. u.mult(nabla,u);
  1653. // Add to viscosity acceleration
  1654. a_visc.vadd( u, a_visc );
  1655. }
  1656. // Calculate force
  1657. a_visc.mult(particle.mass, a_visc);
  1658. a_pressure.mult(particle.mass, a_pressure);
  1659. // Add force to particles
  1660. particle.force.vadd(a_visc, particle.force);
  1661. particle.force.vadd(a_pressure, particle.force);
  1662. }
  1663. };
  1664. // Calculate the weight using the W(r) weightfunction
  1665. CANNON.SPHSystem.prototype.w = function(r){
  1666. // 315
  1667. var h = this.smoothingRadius;
  1668. return 315.0/(64.0*Math.PI*Math.pow(h,9)) * Math.pow(h*h-r*r,3);
  1669. };
  1670. // calculate gradient of the weight function
  1671. CANNON.SPHSystem.prototype.gradw = function(rVec,resultVec){
  1672. var r = rVec.norm(),
  1673. h = this.smoothingRadius;
  1674. rVec.mult(945.0/(32.0*Math.PI*Math.pow(h,9)) * Math.pow((h*h-r*r),2) , resultVec);
  1675. };
  1676. // Calculate nabla(W)
  1677. CANNON.SPHSystem.prototype.nablaw = function(r){
  1678. var h = this.smoothingRadius;
  1679. var nabla = 945.0/(32.0*Math.PI*Math.pow(h,9)) * (h*h-r*r)*(7*r*r - 3*h*h);
  1680. return nabla;
  1681. };
  1682. /**
  1683. * @class CANNON.Box
  1684. * @brief A 3d box shape.
  1685. * @param CANNON.Vec3 halfExtents
  1686. * @author schteppe
  1687. * @extends CANNON.Shape
  1688. */
  1689. CANNON.Box = function(halfExtents){
  1690. CANNON.Shape.call(this);
  1691. /**
  1692. * @property CANNON.Vec3 halfExtents
  1693. * @memberof CANNON.Box
  1694. */
  1695. this.halfExtents = halfExtents;
  1696. this.type = CANNON.Shape.types.BOX;
  1697. /**
  1698. * @property CANNON.ConvexPolyhedron convexPolyhedronRepresentation
  1699. * @brief Used by the contact generator to make contacts with other convex polyhedra for example
  1700. * @memberof CANNON.Box
  1701. */
  1702. this.convexPolyhedronRepresentation = null;
  1703. this.updateConvexPolyhedronRepresentation();
  1704. };
  1705. CANNON.Box.prototype = new CANNON.Shape();
  1706. CANNON.Box.prototype.constructor = CANNON.Box;
  1707. /**
  1708. * @method updateConvexPolyhedronRepresentation
  1709. * @memberof CANNON.Box
  1710. * @brief Updates the local convex polyhedron representation used for some collisions.
  1711. */
  1712. CANNON.Box.prototype.updateConvexPolyhedronRepresentation = function(){
  1713. var sx = this.halfExtents.x;
  1714. var sy = this.halfExtents.y;
  1715. var sz = this.halfExtents.z;
  1716. var V = CANNON.Vec3;
  1717. function createBoxPolyhedron(size){
  1718. size = size || 1;
  1719. var vertices = [new CANNON.Vec3(-size,-size,-size),
  1720. new CANNON.Vec3( size,-size,-size),
  1721. new CANNON.Vec3( size, size,-size),
  1722. new CANNON.Vec3(-size, size,-size),
  1723. new CANNON.Vec3(-size,-size, size),
  1724. new CANNON.Vec3( size,-size, size),
  1725. new CANNON.Vec3( size, size, size),
  1726. new CANNON.Vec3(-size, size, size)];
  1727. var faces =[[3,2,1,0], // -z
  1728. [4,5,6,7], // +z
  1729. [5,4,1,0], // -y
  1730. [2,3,6,7], // +y
  1731. [0,4,7,3 /*0,3,4,7*/ ], // -x
  1732. [1,2,5,6], // +x
  1733. ];
  1734. var faceNormals = [new CANNON.Vec3( 0, 0,-1),
  1735. new CANNON.Vec3( 0, 0, 1),
  1736. new CANNON.Vec3( 0,-1, 0),
  1737. new CANNON.Vec3( 0, 1, 0),
  1738. new CANNON.Vec3(-1, 0, 0),
  1739. new CANNON.Vec3( 1, 0, 0)];
  1740. var boxShape = new CANNON.ConvexPolyhedron(vertices,
  1741. faces,
  1742. faceNormals);
  1743. return boxShape;
  1744. }
  1745. var h = new CANNON.ConvexPolyhedron([new V(-sx,-sy,-sz),
  1746. new V( sx,-sy,-sz),
  1747. new V( sx, sy,-sz),
  1748. new V(-sx, sy,-sz),
  1749. new V(-sx,-sy, sz),
  1750. new V( sx,-sy, sz),
  1751. new V( sx, sy, sz),
  1752. new V(-sx, sy, sz)],
  1753. [[3,2,1,0], // -z
  1754. [4,5,6,7], // +z
  1755. [5,4,1,0], // -y
  1756. [2,3,6,7], // +y
  1757. [0,4,7,3], // -x
  1758. [1,2,5,6], // +x
  1759. ],
  1760. [new V( 0, 0,-1),
  1761. new V( 0, 0, 1),
  1762. new V( 0,-1, 0),
  1763. new V( 0, 1, 0),
  1764. new V(-1, 0, 0),
  1765. new V( 1, 0, 0)]);
  1766. this.convexPolyhedronRepresentation = h;
  1767. };
  1768. CANNON.Box.prototype.calculateLocalInertia = function(mass,target){
  1769. target = target || new CANNON.Vec3();
  1770. var e = this.halfExtents;
  1771. target.x = 1.0 / 12.0 * mass * ( 2*e.y*2*e.y + 2*e.z*2*e.z );
  1772. target.y = 1.0 / 12.0 * mass * ( 2*e.x*2*e.x + 2*e.z*2*e.z );
  1773. target.z = 1.0 / 12.0 * mass * ( 2*e.y*2*e.y + 2*e.x*2*e.x );
  1774. return target;
  1775. };
  1776. /**
  1777. * @method getSideNormals
  1778. * @memberof CANNON.Box
  1779. * @brief Get the box 6 side normals
  1780. * @param bool includeNegative If true, this function returns 6 vectors. If false, it only returns 3 (but you get 6 by reversing those 3)
  1781. * @param CANNON.Quaternion quat Orientation to apply to the normal vectors. If not provided, the vectors will be in respect to the local frame.
  1782. * @return array
  1783. */
  1784. CANNON.Box.prototype.getSideNormals = function(sixTargetVectors,quat){
  1785. var sides = sixTargetVectors;
  1786. var ex = this.halfExtents;
  1787. sides[0].set( ex.x, 0, 0);
  1788. sides[1].set( 0, ex.y, 0);
  1789. sides[2].set( 0, 0, ex.z);
  1790. sides[3].set( -ex.x, 0, 0);
  1791. sides[4].set( 0, -ex.y, 0);
  1792. sides[5].set( 0, 0, -ex.z);
  1793. if(quat!==undefined){
  1794. for(var i=0; i!==sides.length; i++){
  1795. quat.vmult(sides[i],sides[i]);
  1796. }
  1797. }
  1798. return sides;
  1799. };
  1800. CANNON.Box.prototype.volume = function(){
  1801. return 8.0 * this.halfExtents.x * this.halfExtents.y * this.halfExtents.z;
  1802. };
  1803. CANNON.Box.prototype.computeBoundingSphereRadius = function(){
  1804. this.boundingSphereRadius = this.halfExtents.norm();
  1805. this.boundingSphereRadiusNeedsUpdate = false;
  1806. };
  1807. var worldCornerTempPos = new CANNON.Vec3();
  1808. var worldCornerTempNeg = new CANNON.Vec3();
  1809. CANNON.Box.prototype.forEachWorldCorner = function(pos,quat,callback){
  1810. var e = this.halfExtents;
  1811. var corners = [[ e.x, e.y, e.z],
  1812. [ -e.x, e.y, e.z],
  1813. [ -e.x, -e.y, e.z],
  1814. [ -e.x, -e.y, -e.z],
  1815. [ e.x, -e.y, -e.z],
  1816. [ e.x, e.y, -e.z],
  1817. [ -e.x, e.y, -e.z],
  1818. [ e.x, -e.y, e.z]];
  1819. for(var i=0; i<corners.length; i++){
  1820. worldCornerTempPos.set(corners[i][0],corners[i][1],corners[i][2]);
  1821. quat.vmult(worldCornerTempPos,worldCornerTempPos);
  1822. pos.vadd(worldCornerTempPos,worldCornerTempPos);
  1823. callback(worldCornerTempPos.x,
  1824. worldCornerTempPos.y,
  1825. worldCornerTempPos.z);
  1826. }
  1827. };
  1828. CANNON.Box.prototype.calculateWorldAABB = function(pos,quat,min,max){
  1829. // Get each axis max
  1830. min.set(Infinity,Infinity,Infinity);
  1831. max.set(-Infinity,-Infinity,-Infinity);
  1832. this.forEachWorldCorner(pos,quat,function(x,y,z){
  1833. if(x > max.x){
  1834. max.x = x;
  1835. }
  1836. if(y > max.y){
  1837. max.y = y;
  1838. }
  1839. if(z > max.z){
  1840. max.z = z;
  1841. }
  1842. if(x < min.x){
  1843. min.x = x;
  1844. }
  1845. if(y < min.y){
  1846. min.y = y;
  1847. }
  1848. if(z < min.z){
  1849. min.z = z;
  1850. }
  1851. });
  1852. };
  1853. /**
  1854. * @class CANNON.Plane
  1855. * @extends CANNON.Shape
  1856. * @param CANNON.Vec3 normal
  1857. * @brief A plane, facing in the Z direction.
  1858. * @description 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.
  1859. * @author schteppe
  1860. */
  1861. CANNON.Plane = function(){
  1862. CANNON.Shape.call(this);
  1863. this.type = CANNON.Shape.types.PLANE;
  1864. // World oriented normal
  1865. this.worldNormal = new CANNON.Vec3();
  1866. this.worldNormalNeedsUpdate = true;
  1867. };
  1868. CANNON.Plane.prototype = new CANNON.Shape();
  1869. CANNON.Plane.prototype.constructor = CANNON.Plane;
  1870. CANNON.Plane.prototype.computeWorldNormal = function(quat){
  1871. var n = this.worldNormal;
  1872. n.set(0,0,1);
  1873. quat.vmult(n,n);
  1874. this.worldNormalNeedsUpdate = false;
  1875. };
  1876. CANNON.Plane.prototype.calculateLocalInertia = function(mass,target){
  1877. target = target || new CANNON.Vec3();
  1878. return target;
  1879. };
  1880. CANNON.Plane.prototype.volume = function(){
  1881. return Infinity; // The plane is infinite...
  1882. };
  1883. var tempNormal = new CANNON.Vec3();
  1884. CANNON.Plane.prototype.calculateWorldAABB = function(pos,quat,min,max){
  1885. // The plane AABB is infinite, except if the normal is pointing along any axis
  1886. tempNormal.set(0,0,1); // Default plane normal is z
  1887. quat.vmult(tempNormal,tempNormal);
  1888. min.set(-Infinity,-Infinity,-Infinity);
  1889. max.set(Infinity,Infinity,Infinity);
  1890. if(tempNormal.x === 1){ max.x = pos.x; }
  1891. if(tempNormal.y === 1){ max.y = pos.y; }
  1892. if(tempNormal.z === 1){ max.z = pos.z; }
  1893. if(tempNormal.x === -1){ min.x = pos.x; }
  1894. if(tempNormal.y === -1){ min.y = pos.y; }
  1895. if(tempNormal.z === -1){ min.z = pos.z; }
  1896. };
  1897. /**
  1898. * @class CANNON.Compound
  1899. * @extends CANNON.Shape
  1900. * @brief A shape made of several other shapes.
  1901. * @author schteppe
  1902. */
  1903. CANNON.Compound = function(){
  1904. CANNON.Shape.call(this);
  1905. this.type = CANNON.Shape.types.COMPOUND;
  1906. this.childShapes = [];
  1907. this.childOffsets = [];
  1908. this.childOrientations = [];
  1909. };
  1910. CANNON.Compound.prototype = new CANNON.Shape();
  1911. CANNON.Compound.prototype.constructor = CANNON.Compound;
  1912. /**
  1913. * @method addChild
  1914. * @memberof CANNON.Compound
  1915. * @brief Add a child shape.
  1916. * @param CANNON.Shape shape
  1917. * @param CANNON.Vec3 offset
  1918. * @param CANNON.Quaternion orientation
  1919. */
  1920. CANNON.Compound.prototype.addChild = function(shape,offset,orientation){
  1921. offset = offset || new CANNON.Vec3();
  1922. orientation = orientation || new CANNON.Quaternion();
  1923. this.childShapes.push(shape);
  1924. this.childOffsets.push(offset);
  1925. this.childOrientations.push(orientation);
  1926. };
  1927. CANNON.Compound.prototype.volume = function(){
  1928. var r = 0.0;
  1929. var Nchildren = this.childShapes.length;
  1930. for(var i=0; i!==Nchildren; i++){
  1931. r += this.childShapes[i].volume();
  1932. }
  1933. return r;
  1934. };
  1935. var Compound_calculateLocalInertia_mr2 = new CANNON.Vec3();
  1936. var Compound_calculateLocalInertia_childInertia = new CANNON.Vec3();
  1937. CANNON.Compound.prototype.calculateLocalInertia = function(mass,target){
  1938. target = target || new CANNON.Vec3();
  1939. // Calculate the total volume, we will spread out this objects' mass on the sub shapes
  1940. var V = this.volume();
  1941. var childInertia = Compound_calculateLocalInertia_childInertia;
  1942. for(var i=0, Nchildren=this.childShapes.length; i!==Nchildren; i++){
  1943. // Get child information
  1944. var b = this.childShapes[i];
  1945. var o = this.childOffsets[i];
  1946. var q = this.childOrientations[i];
  1947. var m = b.volume() / V * mass;
  1948. // Get the child inertia, transformed relative to local frame
  1949. //var inertia = b.calculateTransformedInertia(m,q);
  1950. b.calculateLocalInertia(m,childInertia); // Todo transform!
  1951. //console.log(childInertia,m,b.volume(),V);
  1952. // Add its inertia using the parallel axis theorem, i.e.
  1953. // I += I_child;
  1954. // I += m_child * r^2
  1955. target.vadd(childInertia,target);
  1956. var mr2 = Compound_calculateLocalInertia_mr2;
  1957. mr2.set(m*o.x*o.x,
  1958. m*o.y*o.y,
  1959. m*o.z*o.z);
  1960. target.vadd(mr2,target);
  1961. }
  1962. return target;
  1963. };
  1964. CANNON.Compound.prototype.computeBoundingSphereRadius = function(){
  1965. var r = 0.0;
  1966. for(var i = 0; i<this.childShapes.length; i++){
  1967. var si = this.childShapes[i];
  1968. if(si.boundingSphereRadiusNeedsUpdate){
  1969. si.computeBoundingSphereRadius();
  1970. }
  1971. var candidate = this.childOffsets[i].norm() + si.boundingSphereRadius;
  1972. if(r < candidate){
  1973. r = candidate;
  1974. }
  1975. }
  1976. this.boundingSphereRadius = r;
  1977. this.boundingSphereRadiusNeedsUpdate = false;
  1978. };
  1979. var aabbmaxTemp = new CANNON.Vec3();
  1980. var aabbminTemp = new CANNON.Vec3();
  1981. var childPosTemp = new CANNON.Vec3();
  1982. var childQuatTemp = new CANNON.Quaternion();
  1983. CANNON.Compound.prototype.calculateWorldAABB = function(pos,quat,min,max){
  1984. var N=this.childShapes.length;
  1985. min.set(Infinity,Infinity,Infinity);
  1986. max.set(-Infinity,-Infinity,-Infinity);
  1987. // Get each axis max
  1988. for(var i=0; i!==N; i++){
  1989. // Accumulate transformation to child
  1990. this.childOffsets[i].copy(childPosTemp);
  1991. quat.vmult(childPosTemp,childPosTemp);
  1992. pos.vadd(childPosTemp,childPosTemp);
  1993. quat.mult(this.childOrientations[i],childQuatTemp);
  1994. // Get child AABB
  1995. this.childShapes[i].calculateWorldAABB(childPosTemp,
  1996. childQuatTemp,//this.childOrientations[i],
  1997. aabbminTemp,
  1998. aabbmaxTemp);
  1999. if(aabbminTemp.x < min.x){
  2000. min.x = aabbminTemp.x;
  2001. }
  2002. if(aabbminTemp.y < min.y){
  2003. min.y = aabbminTemp.y;
  2004. }
  2005. if(aabbminTemp.z < min.z){
  2006. min.z = aabbminTemp.z;
  2007. }
  2008. if(aabbmaxTemp.x > max.x){
  2009. max.x = aabbmaxTemp.x;
  2010. }
  2011. if(aabbmaxTemp.y > max.y){
  2012. max.y = aabbmaxTemp.y;
  2013. }
  2014. if(aabbmaxTemp.z > max.z){
  2015. max.z = aabbmaxTemp.z;
  2016. }
  2017. }
  2018. };
  2019. /**
  2020. * @class CANNON.ConvexPolyhedron
  2021. * @extends CANNON.Shape
  2022. * @brief A set of points in space describing a convex shape.
  2023. * @author qiao / https://github.com/qiao (original author, see https://github.com/qiao/three.js/commit/85026f0c769e4000148a67d45a9e9b9c5108836f)
  2024. * @author schteppe / https://github.com/schteppe
  2025. * @see http://www.altdevblogaday.com/2011/05/13/contact-generation-between-3d-convex-meshes/
  2026. * @see http://bullet.googlecode.com/svn/trunk/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
  2027. * @todo move the clipping functions to ContactGenerator?
  2028. * @param array points An array of CANNON.Vec3's
  2029. * @param array faces
  2030. * @param array normals
  2031. */
  2032. CANNON.ConvexPolyhedron = function( points , faces , normals ) {
  2033. var that = this;
  2034. CANNON.Shape.call( this );
  2035. this.type = CANNON.Shape.types.CONVEXPOLYHEDRON;
  2036. /*
  2037. * @brief Get face normal given 3 vertices
  2038. * @param CANNON.Vec3 va
  2039. * @param CANNON.Vec3 vb
  2040. * @param CANNON.Vec3 vc
  2041. * @param CANNON.Vec3 target
  2042. * @todo unit test?
  2043. */
  2044. var cb = new CANNON.Vec3();
  2045. var ab = new CANNON.Vec3();
  2046. function normal( va, vb, vc, target ) {
  2047. vb.vsub(va,ab);
  2048. vc.vsub(vb,cb);
  2049. cb.cross(ab,target);
  2050. if ( !target.isZero() ) {
  2051. target.normalize();
  2052. }
  2053. }
  2054. /**
  2055. * @property array vertices
  2056. * @memberof CANNON.ConvexPolyhedron
  2057. * @brief Array of CANNON.Vec3
  2058. */
  2059. this.vertices = points||[];
  2060. this.worldVertices = []; // World transformed version of .vertices
  2061. this.worldVerticesNeedsUpdate = true;
  2062. /**
  2063. * @property array faces
  2064. * @memberof CANNON.ConvexPolyhedron
  2065. * @brief Array of integer arrays, indicating which vertices each face consists of
  2066. * @todo Needed?
  2067. */
  2068. this.faces = faces||[];
  2069. /**
  2070. * @property array faceNormals
  2071. * @memberof CANNON.ConvexPolyhedron
  2072. * @brief Array of CANNON.Vec3
  2073. * @todo Needed?
  2074. */
  2075. this.faceNormals = [];//normals||[];
  2076. /*
  2077. for(var i=0; i<this.faceNormals.length; i++){
  2078. this.faceNormals[i].normalize();
  2079. }
  2080. */
  2081. // Generate normals
  2082. for(var i=0; i<this.faces.length; i++){
  2083. // Check so all vertices exists for this face
  2084. for(var j=0; j<this.faces[i].length; j++){
  2085. if(!this.vertices[this.faces[i][j]]){
  2086. throw new Error("Vertex "+this.faces[i][j]+" not found!");
  2087. }
  2088. }
  2089. var n = new CANNON.Vec3();
  2090. normalOfFace(i,n);
  2091. n.negate(n);
  2092. this.faceNormals.push(n);
  2093. //console.log(n.toString());
  2094. var vertex = this.vertices[this.faces[i][0]];
  2095. if(n.dot(vertex)<0){
  2096. console.warn("Face normal "+i+" ("+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.");
  2097. for(var j=0; j<this.faces[i].length; j++){
  2098. console.warn("Vertex "+this.faces[i][j]+": ("+this.vertices[faces[i][j]].toString()+")");
  2099. }
  2100. }
  2101. }
  2102. this.worldFaceNormalsNeedsUpdate = true;
  2103. this.worldFaceNormals = []; // World transformed version of .faceNormals
  2104. /**
  2105. * @property array uniqueEdges
  2106. * @memberof CANNON.ConvexPolyhedron
  2107. * @brief Array of CANNON.Vec3
  2108. */
  2109. this.uniqueEdges = [];
  2110. var nv = this.vertices.length;
  2111. for(var pi=0; pi<nv; pi++){
  2112. var p = this.vertices[pi];
  2113. if(!(p instanceof CANNON.Vec3)){
  2114. throw "Argument 1 must be instance of CANNON.Vec3";
  2115. }
  2116. this.uniqueEdges.push(p);
  2117. }
  2118. for(var i=0; i<this.faces.length; i++){
  2119. var numVertices = this.faces[i].length;
  2120. var NbTris = numVertices;
  2121. for(var j=0; j<NbTris; j++){
  2122. var k = ( j+1 ) % numVertices;
  2123. var edge = new CANNON.Vec3();
  2124. this.vertices[this.faces[i][j]].vsub(this.vertices[this.faces[i][k]],edge);
  2125. edge.normalize();
  2126. var found = false;
  2127. for(var p=0;p<this.uniqueEdges.length;p++){
  2128. if (this.uniqueEdges[p].almostEquals(edge) || this.uniqueEdges[p].almostEquals(edge)){
  2129. found = true;
  2130. break;
  2131. }
  2132. }
  2133. if (!found){
  2134. this.uniqueEdges.push(edge);
  2135. }
  2136. if (edge) {
  2137. edge.face1 = i;
  2138. } else {
  2139. /*
  2140. var ed;
  2141. ed.m_face0 = i;
  2142. edges.insert(vp,ed);
  2143. */
  2144. }
  2145. }
  2146. }
  2147. /*
  2148. * 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.
  2149. * @param CANNON.ConvexPolyhedron hull
  2150. * @param CANNON.Vec3 axis
  2151. * @param CANNON.Vec3 pos
  2152. * @param CANNON.Quaternion quat
  2153. * @param array maxmin maxmin[0] and maxmin[1] will be set to maximum and minimum, respectively.
  2154. */
  2155. var worldVertex = new CANNON.Vec3();
  2156. function project(hull,axis,pos,quat,maxmin){
  2157. var n = hull.vertices.length;
  2158. var max = null;
  2159. var min = null;
  2160. var vs = hull.vertices;
  2161. for(var i=0; i<n; i++){
  2162. vs[i].copy(worldVertex);
  2163. quat.vmult(worldVertex,worldVertex);
  2164. worldVertex.vadd(pos,worldVertex);
  2165. var val = worldVertex.dot(axis);
  2166. if(max===null || val>max){
  2167. max = val;
  2168. }
  2169. if(min===null || val<min){
  2170. min = val;
  2171. }
  2172. }
  2173. if(min>max){
  2174. // Inconsistent - swap
  2175. var temp = min;
  2176. min = max;
  2177. max = temp;
  2178. }
  2179. // Output
  2180. maxmin[0] = max;
  2181. maxmin[1] = min;
  2182. }
  2183. /**
  2184. * @method testSepAxis
  2185. * @memberof CANNON.ConvexPolyhedron
  2186. * @brief Test separating axis against two hulls. Both hulls are projected onto the axis and the overlap size is returned if there is one.
  2187. * @param CANNON.Vec3 axis
  2188. * @param CANNON.ConvexPolyhedron hullB
  2189. * @param CANNON.Vec3 posA
  2190. * @param CANNON.Quaternion quatA
  2191. * @param CANNON.Vec3 posB
  2192. * @param CANNON.Quaternion quatB
  2193. * @return float The overlap depth, or FALSE if no penetration.
  2194. */
  2195. this.testSepAxis = function(axis, hullB, posA, quatA, posB, quatB){
  2196. var maxminA=[], maxminB=[], hullA=this;
  2197. project(hullA, axis, posA, quatA, maxminA);
  2198. project(hullB, axis, posB, quatB, maxminB);
  2199. var maxA = maxminA[0];
  2200. var minA = maxminA[1];
  2201. var maxB = maxminB[0];
  2202. var minB = maxminB[1];
  2203. if(maxA<minB || maxB<minA){
  2204. //console.log(minA,maxA,minB,maxB);
  2205. return false; // Separated
  2206. }
  2207. var d0 = maxA - minB;
  2208. var d1 = maxB - minA;
  2209. var depth = d0<d1 ? d0:d1;
  2210. return depth;
  2211. };
  2212. /**
  2213. * @method findSeparatingAxis
  2214. * @memberof CANNON.ConvexPolyhedron
  2215. * @brief Find the separating axis between this hull and another
  2216. * @param CANNON.ConvexPolyhedron hullB
  2217. * @param CANNON.Vec3 posA
  2218. * @param CANNON.Quaternion quatA
  2219. * @param CANNON.Vec3 posB
  2220. * @param CANNON.Quaternion quatB
  2221. * @param CANNON.Vec3 target The target vector to save the axis in
  2222. * @return bool Returns false if a separation is found, else true
  2223. */
  2224. var faceANormalWS3 = new CANNON.Vec3();
  2225. var Worldnormal1 = new CANNON.Vec3();
  2226. var deltaC = new CANNON.Vec3();
  2227. var worldEdge0 = new CANNON.Vec3();
  2228. var worldEdge1 = new CANNON.Vec3();
  2229. var Cross = new CANNON.Vec3();
  2230. this.findSeparatingAxis = function(hullB,posA,quatA,posB,quatB,target){
  2231. var dmin = Infinity;
  2232. var hullA = this;
  2233. var curPlaneTests=0;
  2234. var numFacesA = hullA.faces.length;
  2235. // Test normals from hullA
  2236. for(var i=0; i<numFacesA; i++){
  2237. // Get world face normal
  2238. hullA.faceNormals[i].copy(faceANormalWS3);
  2239. quatA.vmult(faceANormalWS3,faceANormalWS3);
  2240. //posA.vadd(faceANormalWS3,faceANormalWS3); // Needed?
  2241. //console.log("face normal:",hullA.faceNormals[i].toString(),"world face normal:",faceANormalWS3);
  2242. var d = hullA.testSepAxis(faceANormalWS3, hullB, posA, quatA, posB, quatB);
  2243. if(d===false){
  2244. return false;
  2245. }
  2246. if(d<dmin){
  2247. dmin = d;
  2248. faceANormalWS3.copy(target);
  2249. }
  2250. }
  2251. // Test normals from hullB
  2252. var numFacesB = hullB.faces.length;
  2253. for(var i=0;i<numFacesB;i++){
  2254. hullB.faceNormals[i].copy(Worldnormal1);
  2255. quatB.vmult(Worldnormal1,Worldnormal1);
  2256. //posB.vadd(Worldnormal1,Worldnormal1);
  2257. //console.log("facenormal",hullB.faceNormals[i].toString(),"world:",Worldnormal1.toString());
  2258. curPlaneTests++;
  2259. var d = hullA.testSepAxis(Worldnormal1, hullB,posA,quatA,posB,quatB);
  2260. if(d===false){
  2261. return false;
  2262. }
  2263. if(d<dmin){
  2264. dmin = d;
  2265. Worldnormal1.copy(target);
  2266. }
  2267. }
  2268. var edgeAstart,edgeAend,edgeBstart,edgeBend;
  2269. var curEdgeEdge = 0;
  2270. // Test edges
  2271. for(var e0=0; e0<hullA.uniqueEdges.length; e0++){
  2272. // Get world edge
  2273. hullA.uniqueEdges[e0].copy(worldEdge0);
  2274. quatA.vmult(worldEdge0,worldEdge0);
  2275. //posA.vadd(worldEdge0,worldEdge0); // needed?
  2276. //console.log("edge0:",worldEdge0.toString());
  2277. for(var e1=0; e1<hullB.uniqueEdges.length; e1++){
  2278. hullB.uniqueEdges[e1].copy(worldEdge1);
  2279. quatB.vmult(worldEdge1,worldEdge1);
  2280. //posB.vadd(worldEdge1,worldEdge1); // needed?
  2281. //console.log("edge1:",worldEdge1.toString());
  2282. worldEdge0.cross(worldEdge1,Cross);
  2283. curEdgeEdge++;
  2284. if(!Cross.almostZero()){
  2285. Cross.normalize();
  2286. var dist = hullA.testSepAxis( Cross, hullB, posA,quatA,posB,quatB);
  2287. if(dist===false){
  2288. return false;
  2289. }
  2290. if(dist<dmin){
  2291. dmin = dist;
  2292. Cross.copy(target);
  2293. }
  2294. }
  2295. }
  2296. }
  2297. posB.vsub(posA,deltaC);
  2298. if((deltaC.dot(target))>0.0){
  2299. target.negate(target);
  2300. }
  2301. return true;
  2302. };
  2303. /**
  2304. * @method clipAgainstHull
  2305. * @memberof CANNON.ConvexPolyhedron
  2306. * @brief Clip this hull against another hull
  2307. * @param CANNON.Vec3 posA
  2308. * @param CANNON.Quaternion quatA
  2309. * @param CANNON.ConvexPolyhedron hullB
  2310. * @param CANNON.Vec3 posB
  2311. * @param CANNON.Quaternion quatB
  2312. * @param CANNON.Vec3 separatingNormal
  2313. * @param float minDist Clamp distance
  2314. * @param float maxDist
  2315. * @param array result The an array of contact point objects, see clipFaceAgainstHull
  2316. * @see http://bullet.googlecode.com/svn/trunk/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
  2317. */
  2318. var WorldNormal = new CANNON.Vec3();
  2319. this.clipAgainstHull = function(posA,quatA,hullB,posB,quatB,separatingNormal,minDist,maxDist,result){
  2320. if(!(posA instanceof CANNON.Vec3)){
  2321. throw new Error("posA must be Vec3");
  2322. }
  2323. if(!(quatA instanceof CANNON.Quaternion)){
  2324. throw new Error("quatA must be Quaternion");
  2325. }
  2326. var hullA = this;
  2327. var curMaxDist = maxDist;
  2328. var closestFaceB = -1;
  2329. var dmax = -Infinity;
  2330. for(var face=0; face < hullB.faces.length; face++){
  2331. hullB.faceNormals[face].copy(WorldNormal);
  2332. quatB.vmult(WorldNormal,WorldNormal);
  2333. //posB.vadd(WorldNormal,WorldNormal);
  2334. var d = WorldNormal.dot(separatingNormal);
  2335. if (d > dmax){
  2336. dmax = d;
  2337. closestFaceB = face;
  2338. }
  2339. }
  2340. var worldVertsB1 = [];
  2341. var polyB = hullB.faces[closestFaceB];
  2342. var numVertices = polyB.length;
  2343. for(var e0=0; e0<numVertices; e0++){
  2344. var b = hullB.vertices[polyB[e0]];
  2345. var worldb = new CANNON.Vec3();
  2346. b.copy(worldb);
  2347. quatB.vmult(worldb,worldb);
  2348. posB.vadd(worldb,worldb);
  2349. worldVertsB1.push(worldb);
  2350. }
  2351. if (closestFaceB>=0){
  2352. this.clipFaceAgainstHull(separatingNormal,
  2353. posA,
  2354. quatA,
  2355. worldVertsB1,
  2356. minDist,
  2357. maxDist,
  2358. result);
  2359. }
  2360. };
  2361. /**
  2362. * @method clipFaceAgainstHull
  2363. * @memberof CANNON.ConvexPolyhedron
  2364. * @brief Clip a face against a hull.
  2365. * @param CANNON.Vec3 separatingNormal
  2366. * @param CANNON.Vec3 posA
  2367. * @param CANNON.Quaternion quatA
  2368. * @param Array worldVertsB1 An array of CANNON.Vec3 with vertices in the world frame.
  2369. * @param float minDist Distance clamping
  2370. * @param float maxDist
  2371. * @param Array result Array to store resulting contact points in. Will be objects with properties: point, depth, normal. These are represented in world coordinates.
  2372. */
  2373. var faceANormalWS = new CANNON.Vec3();
  2374. var edge0 = new CANNON.Vec3();
  2375. var WorldEdge0 = new CANNON.Vec3();
  2376. var worldPlaneAnormal1 = new CANNON.Vec3();
  2377. var planeNormalWS1 = new CANNON.Vec3();
  2378. var worldA1 = new CANNON.Vec3();
  2379. var localPlaneNormal = new CANNON.Vec3();
  2380. var planeNormalWS = new CANNON.Vec3();
  2381. this.clipFaceAgainstHull = function(separatingNormal, posA, quatA, worldVertsB1, minDist, maxDist,result){
  2382. if(!(separatingNormal instanceof CANNON.Vec3)){
  2383. throw new Error("sep normal must be vector");
  2384. }
  2385. if(!(worldVertsB1 instanceof Array)){
  2386. throw new Error("world verts must be array");
  2387. }
  2388. minDist = Number(minDist);
  2389. maxDist = Number(maxDist);
  2390. var hullA = this;
  2391. var worldVertsB2 = [];
  2392. var pVtxIn = worldVertsB1;
  2393. var pVtxOut = worldVertsB2;
  2394. // Find the face with normal closest to the separating axis
  2395. var closestFaceA = -1;
  2396. var dmin = Infinity;
  2397. for(var face=0; face<hullA.faces.length; face++){
  2398. hullA.faceNormals[face].copy(faceANormalWS);
  2399. quatA.vmult(faceANormalWS,faceANormalWS);
  2400. //posA.vadd(faceANormalWS,faceANormalWS);
  2401. var d = faceANormalWS.dot(separatingNormal);
  2402. if (d < dmin){
  2403. dmin = d;
  2404. closestFaceA = face;
  2405. }
  2406. }
  2407. if (closestFaceA<0){
  2408. console.log("--- did not find any closest face... ---");
  2409. return;
  2410. }
  2411. //console.log("closest A: ",closestFaceA);
  2412. // Get the face and construct connected faces
  2413. var polyA = hullA.faces[closestFaceA];
  2414. polyA.connectedFaces = [];
  2415. for(var i=0; i<hullA.faces.length; i++){
  2416. for(var j=0; j<hullA.faces[i].length; j++){
  2417. 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 */ ){
  2418. polyA.connectedFaces.push(i);
  2419. }
  2420. }
  2421. }
  2422. // Clip the polygon to the back of the planes of all faces of hull A, that are adjacent to the witness face
  2423. var numContacts = pVtxIn.length;
  2424. var numVerticesA = polyA.length;
  2425. var res = [];
  2426. for(var e0=0; e0<numVerticesA; e0++){
  2427. var a = hullA.vertices[polyA[e0]];
  2428. var b = hullA.vertices[polyA[(e0+1)%numVerticesA]];
  2429. a.vsub(b,edge0);
  2430. edge0.copy(WorldEdge0);
  2431. quatA.vmult(WorldEdge0,WorldEdge0);
  2432. posA.vadd(WorldEdge0,WorldEdge0);
  2433. this.faceNormals[closestFaceA].copy(worldPlaneAnormal1);//transA.getBasis()* btVector3(polyA.m_plane[0],polyA.m_plane[1],polyA.m_plane[2]);
  2434. quatA.vmult(worldPlaneAnormal1,worldPlaneAnormal1);
  2435. posA.vadd(worldPlaneAnormal1,worldPlaneAnormal1);
  2436. WorldEdge0.cross(worldPlaneAnormal1,planeNormalWS1);
  2437. planeNormalWS1.negate(planeNormalWS1);
  2438. a.copy(worldA1);
  2439. quatA.vmult(worldA1,worldA1);
  2440. posA.vadd(worldA1,worldA1);
  2441. var planeEqWS1 = -worldA1.dot(planeNormalWS1);
  2442. var planeEqWS;
  2443. if(true){
  2444. var otherFace = polyA.connectedFaces[e0];
  2445. this.faceNormals[otherFace].copy(localPlaneNormal);
  2446. var localPlaneEq = planeConstant(otherFace);
  2447. localPlaneNormal.copy(planeNormalWS);
  2448. quatA.vmult(planeNormalWS,planeNormalWS);
  2449. //posA.vadd(planeNormalWS,planeNormalWS);
  2450. var planeEqWS = localPlaneEq - planeNormalWS.dot(posA);
  2451. } else {
  2452. planeNormalWS1.copy(planeNormalWS);
  2453. planeEqWS = planeEqWS1;
  2454. }
  2455. // Clip face against our constructed plane
  2456. //console.log("clipping polygon ",printFace(closestFaceA)," against plane ",planeNormalWS, planeEqWS);
  2457. this.clipFaceAgainstPlane(pVtxIn, pVtxOut, planeNormalWS, planeEqWS);
  2458. //console.log(" - clip result: ",pVtxOut);
  2459. // Throw away all clipped points, but save the reamining until next clip
  2460. while(pVtxIn.length){
  2461. pVtxIn.shift();
  2462. }
  2463. while(pVtxOut.length){
  2464. pVtxIn.push(pVtxOut.shift());
  2465. }
  2466. }
  2467. //console.log("Resulting points after clip:",pVtxIn);
  2468. // only keep contact points that are behind the witness face
  2469. this.faceNormals[closestFaceA].copy(localPlaneNormal);
  2470. var localPlaneEq = planeConstant(closestFaceA);
  2471. localPlaneNormal.copy(planeNormalWS);
  2472. quatA.vmult(planeNormalWS,planeNormalWS);
  2473. var planeEqWS = localPlaneEq - planeNormalWS.dot(posA);
  2474. for (var i=0; i<pVtxIn.length; i++){
  2475. var depth = planeNormalWS.dot(pVtxIn[i]) + planeEqWS; //???
  2476. /*console.log("depth calc from normal=",planeNormalWS.toString()," and constant "+planeEqWS+" and vertex ",pVtxIn[i].toString()," gives "+depth);*/
  2477. if (depth <=minDist){
  2478. console.log("clamped: depth="+depth+" to minDist="+(minDist+""));
  2479. depth = minDist;
  2480. }
  2481. if (depth <=maxDist){
  2482. var point = pVtxIn[i];
  2483. if(depth<=0){
  2484. /*console.log("Got contact point ",point.toString(),
  2485. ", depth=",depth,
  2486. "contact normal=",separatingNormal.toString(),
  2487. "plane",planeNormalWS.toString(),
  2488. "planeConstant",planeEqWS);*/
  2489. var p = {
  2490. point:point,
  2491. normal:planeNormalWS,
  2492. depth: depth,
  2493. };
  2494. result.push(p);
  2495. }
  2496. }
  2497. }
  2498. };
  2499. /**
  2500. * @method clipFaceAgainstPlane
  2501. * @memberof CANNON.ConvexPolyhedron
  2502. * @brief Clip a face in a hull against the back of a plane.
  2503. * @param Array inVertices
  2504. * @param Array outVertices
  2505. * @param CANNON.Vec3 planeNormal
  2506. * @param float planeConstant The constant in the mathematical plane equation
  2507. */
  2508. this.clipFaceAgainstPlane = function(inVertices,outVertices, planeNormal, planeConstant){
  2509. if(!(planeNormal instanceof CANNON.Vec3)){
  2510. throw new Error("planeNormal must be Vec3, "+planeNormal+" given");
  2511. }
  2512. if(!(inVertices instanceof Array)) {
  2513. throw new Error("invertices must be Array, "+inVertices+" given");
  2514. }
  2515. if(!(outVertices instanceof Array)){
  2516. throw new Error("outvertices must be Array, "+outVertices+" given");
  2517. }
  2518. var n_dot_first, n_dot_last;
  2519. var numVerts = inVertices.length;
  2520. if(numVerts < 2){
  2521. return outVertices;
  2522. }
  2523. var firstVertex = inVertices[inVertices.length-1];
  2524. var lastVertex = inVertices[0];
  2525. n_dot_first = planeNormal.dot(firstVertex) + planeConstant;
  2526. for(var vi = 0; vi < numVerts; vi++){
  2527. lastVertex = inVertices[vi];
  2528. n_dot_last = planeNormal.dot(lastVertex) + planeConstant;
  2529. if(n_dot_first < 0){
  2530. if(n_dot_last < 0){
  2531. // Start < 0, end < 0, so output lastVertex
  2532. var newv = new CANNON.Vec3();
  2533. lastVertex.copy(newv);
  2534. outVertices.push(newv);
  2535. } else {
  2536. // Start < 0, end >= 0, so output intersection
  2537. var newv = new CANNON.Vec3();
  2538. firstVertex.lerp(lastVertex,
  2539. n_dot_first / (n_dot_first - n_dot_last),
  2540. newv);
  2541. outVertices.push(newv);
  2542. }
  2543. } else {
  2544. if(n_dot_last<0){
  2545. // Start >= 0, end < 0 so output intersection and end
  2546. var newv = new CANNON.Vec3();
  2547. firstVertex.lerp(lastVertex,
  2548. n_dot_first / (n_dot_first - n_dot_last),
  2549. newv);
  2550. outVertices.push(newv);
  2551. outVertices.push(lastVertex);
  2552. }
  2553. }
  2554. firstVertex = lastVertex;
  2555. n_dot_first = n_dot_last;
  2556. }
  2557. return outVertices;
  2558. };
  2559. var that = this;
  2560. function normalOfFace(i,target){
  2561. var f = that.faces[i];
  2562. var va = that.vertices[f[0]];
  2563. var vb = that.vertices[f[1]];
  2564. var vc = that.vertices[f[2]];
  2565. return normal(va,vb,vc,target);
  2566. }
  2567. function planeConstant(face_i,target){
  2568. var f = that.faces[face_i];
  2569. var n = that.faceNormals[face_i];
  2570. var v = that.vertices[f[0]];
  2571. var c = -n.dot(v);
  2572. return c;
  2573. }
  2574. function printFace(i){
  2575. var f = that.faces[i], s = "";
  2576. for(var j=0; j<f.length; j++){
  2577. s += " ("+that.vertices[f[j]]+")";
  2578. }
  2579. return s;
  2580. }
  2581. /*
  2582. * Detect whether two edges are equal.
  2583. * Note that when constructing the convex hull, two same edges can only
  2584. * be of the negative direction.
  2585. * @return bool
  2586. */
  2587. function equalEdge( ea, eb ) {
  2588. return ea[ 0 ] === eb[ 1 ] && ea[ 1 ] === eb[ 0 ];
  2589. }
  2590. /*
  2591. * Create a random offset between -1e-6 and 1e-6.
  2592. * @return float
  2593. */
  2594. function randomOffset() {
  2595. return ( Math.random() - 0.5 ) * 2 * 1e-6;
  2596. }
  2597. this.calculateLocalInertia = function(mass,target){
  2598. // Approximate with box inertia
  2599. // Exact inertia calculation is overkill, but see http://geometrictools.com/Documentation/PolyhedralMassProperties.pdf for the correct way to do it
  2600. that.computeAABB();
  2601. var x = this.aabbmax.x - this.aabbmin.x,
  2602. y = this.aabbmax.y - this.aabbmin.y,
  2603. z = this.aabbmax.z - this.aabbmin.z;
  2604. target.x = 1.0 / 12.0 * mass * ( 2*y*2*y + 2*z*2*z );
  2605. target.y = 1.0 / 12.0 * mass * ( 2*x*2*x + 2*z*2*z );
  2606. target.z = 1.0 / 12.0 * mass * ( 2*y*2*y + 2*x*2*x );
  2607. };
  2608. var worldVert = new CANNON.Vec3();
  2609. this.computeAABB = function(){
  2610. var n = this.vertices.length,
  2611. aabbmin = this.aabbmin,
  2612. aabbmax = this.aabbmax,
  2613. vertices = this.vertices;
  2614. aabbmin.set(Infinity,Infinity,Infinity);
  2615. aabbmax.set(-Infinity,-Infinity,-Infinity);
  2616. for(var i=0; i<n; i++){
  2617. var v = vertices[i];
  2618. if (v.x < aabbmin.x){
  2619. aabbmin.x = v.x;
  2620. } else if(v.x > aabbmax.x){
  2621. aabbmax.x = v.x;
  2622. }
  2623. if (v.y < aabbmin.y){
  2624. aabbmin.y = v.y;
  2625. } else if(v.y > aabbmax.y){
  2626. aabbmax.y = v.y;
  2627. }
  2628. if (v.z < aabbmin.z){
  2629. aabbmin.z = v.z;
  2630. } else if(v.z > aabbmax.z){
  2631. aabbmax.z = v.z;
  2632. }
  2633. }
  2634. };
  2635. //this.computeAABB();
  2636. };
  2637. CANNON.ConvexPolyhedron.prototype = new CANNON.Shape();
  2638. CANNON.ConvexPolyhedron.prototype.constructor = CANNON.ConvexPolyhedron;
  2639. // Updates .worldVertices and sets .worldVerticesNeedsUpdate to false.
  2640. CANNON.ConvexPolyhedron.prototype.computeWorldVertices = function(position,quat){
  2641. var N = this.vertices.length;
  2642. while(this.worldVertices.length < N){
  2643. this.worldVertices.push( new CANNON.Vec3() );
  2644. }
  2645. var verts = this.vertices,
  2646. worldVerts = this.worldVertices;
  2647. for(var i=0; i!==N; i++){
  2648. quat.vmult( verts[i] , worldVerts[i] );
  2649. position.vadd( worldVerts[i] , worldVerts[i] );
  2650. }
  2651. this.worldVerticesNeedsUpdate = false;
  2652. };
  2653. // Updates .worldVertices and sets .worldVerticesNeedsUpdate to false.
  2654. CANNON.ConvexPolyhedron.prototype.computeWorldFaceNormals = function(quat){
  2655. var N = this.faceNormals.length;
  2656. while(this.worldFaceNormals.length < N){
  2657. this.worldFaceNormals.push( new CANNON.Vec3() );
  2658. }
  2659. var normals = this.faceNormals,
  2660. worldNormals = this.worldFaceNormals;
  2661. for(var i=0; i!==N; i++){
  2662. quat.vmult( normals[i] , worldNormals[i] );
  2663. }
  2664. this.worldFaceNormalsNeedsUpdate = false;
  2665. };
  2666. CANNON.ConvexPolyhedron.prototype.computeBoundingSphereRadius = function(){
  2667. // Assume points are distributed with local (0,0,0) as center
  2668. var max2 = 0;
  2669. var verts = this.vertices;
  2670. for(var i=0, N=verts.length; i!==N; i++) {
  2671. var norm2 = verts[i].norm2();
  2672. if(norm2 > max2){
  2673. max2 = norm2;
  2674. }
  2675. }
  2676. this.boundingSphereRadius = Math.sqrt(max2);
  2677. this.boundingSphereRadiusNeedsUpdate = false;
  2678. };
  2679. var tempWorldVertex = new CANNON.Vec3();
  2680. CANNON.ConvexPolyhedron.prototype.calculateWorldAABB = function(pos,quat,min,max){
  2681. var n = this.vertices.length, verts = this.vertices;
  2682. var minx,miny,minz,maxx,maxy,maxz;
  2683. for(var i=0; i<n; i++){
  2684. verts[i].copy(tempWorldVertex);
  2685. quat.vmult(tempWorldVertex,tempWorldVertex);
  2686. pos.vadd(tempWorldVertex,tempWorldVertex);
  2687. var v = tempWorldVertex;
  2688. if (v.x < minx || minx===undefined){
  2689. minx = v.x;
  2690. } else if(v.x > maxx || maxx===undefined){
  2691. maxx = v.x;
  2692. }
  2693. if (v.y < miny || miny===undefined){
  2694. miny = v.y;
  2695. } else if(v.y > maxy || maxy===undefined){
  2696. maxy = v.y;
  2697. }
  2698. if (v.z < minz || minz===undefined){
  2699. minz = v.z;
  2700. } else if(v.z > maxz || maxz===undefined){
  2701. maxz = v.z;
  2702. }
  2703. }
  2704. min.set(minx,miny,minz);
  2705. max.set(maxx,maxy,maxz);
  2706. };
  2707. // Just approximate volume!
  2708. CANNON.ConvexPolyhedron.prototype.volume = function(){
  2709. if(this.boundingSphereRadiusNeedsUpdate){
  2710. this.computeBoundingSphereRadius();
  2711. }
  2712. return 4.0 * Math.PI * this.boundingSphereRadius / 3.0;
  2713. };
  2714. // Get an average of all the vertices
  2715. CANNON.ConvexPolyhedron.prototype.getAveragePointLocal = function(target){
  2716. target = target || new CANNON.Vec3();
  2717. var n = this.vertices.length,
  2718. verts = this.vertices;
  2719. for(var i=0; i<n; i++){
  2720. target.vadd(verts[i],target);
  2721. }
  2722. target.mult(1/n,target);
  2723. return target;
  2724. };
  2725. // Transforms all points
  2726. CANNON.ConvexPolyhedron.prototype.transformAllPoints = function(offset,quat){
  2727. var n = this.vertices.length,
  2728. verts = this.vertices;
  2729. // Apply rotation
  2730. if(quat){
  2731. // Rotate vertices
  2732. for(var i=0; i<n; i++){
  2733. var v = verts[i];
  2734. quat.vmult(v,v);
  2735. }
  2736. // Rotate face normals
  2737. for(var i=0; i<this.faceNormals.length; i++){
  2738. var v = this.faceNormals[i];
  2739. quat.vmult(v,v);
  2740. }
  2741. /*
  2742. // Rotate edges
  2743. for(var i=0; i<this.uniqueEdges.length; i++){
  2744. var v = this.uniqueEdges[i];
  2745. quat.vmult(v,v);
  2746. }*/
  2747. }
  2748. // Apply offset
  2749. if(offset){
  2750. for(var i=0; i<n; i++){
  2751. var v = verts[i];
  2752. v.vadd(offset,v);
  2753. }
  2754. }
  2755. };
  2756. // Checks whether p is inside the polyhedra. Must be in local coords.
  2757. // The point lies outside of the convex hull of the other points
  2758. // if and only if the direction of all the vectors from it to those
  2759. // other points are on less than one half of a sphere around it.
  2760. var ConvexPolyhedron_pointIsInside = new CANNON.Vec3();
  2761. var ConvexPolyhedron_vToP = new CANNON.Vec3();
  2762. var ConvexPolyhedron_vToPointInside = new CANNON.Vec3();
  2763. CANNON.ConvexPolyhedron.prototype.pointIsInside = function(p){
  2764. var n = this.vertices.length,
  2765. verts = this.vertices,
  2766. faces = this.faces,
  2767. normals = this.faceNormals;
  2768. var positiveResult = null;
  2769. var N = this.faces.length;
  2770. var pointInside = ConvexPolyhedron_pointIsInside;
  2771. this.getAveragePointLocal(pointInside);
  2772. for(var i=0; i<N; i++){
  2773. var numVertices = this.faces[i].length;
  2774. var n = normals[i];
  2775. var v = verts[faces[i][0]]; // We only need one point in the face
  2776. // This dot product determines which side of the edge the point is
  2777. var vToP = ConvexPolyhedron_vToP;
  2778. p.vsub(v,vToP);
  2779. var r1 = n.dot(vToP);
  2780. var vToPointInside = ConvexPolyhedron_vToPointInside;
  2781. pointInside.vsub(v,vToPointInside);
  2782. var r2 = n.dot(vToPointInside);
  2783. if((r1<0 && r2>0) || (r1>0 && r2<0)){
  2784. return false; // Encountered some other sign. Exit.
  2785. } else {
  2786. }
  2787. }
  2788. // If we got here, all dot products were of the same sign.
  2789. return positiveResult ? 1 : -1;
  2790. };
  2791. function pointInConvex(p){
  2792. }
  2793. /**
  2794. * @class CANNON.Cylinder
  2795. * @extends CANNON.ConvexPolyhedron
  2796. * @author schteppe / https://github.com/schteppe
  2797. * @param float radiusTop
  2798. * @param float radiusBottom
  2799. * @param float height
  2800. * @param int numSegments The number of segments to build the cylinder out of
  2801. */
  2802. CANNON.Cylinder = function( radiusTop, radiusBottom, height , numSegments ) {
  2803. var N = numSegments,
  2804. verts = [],
  2805. normals = [],
  2806. faces = [],
  2807. bottomface = [],
  2808. topface = [],
  2809. cos = Math.cos,
  2810. sin = Math.sin;
  2811. // First bottom point
  2812. verts.push(new CANNON.Vec3(radiusBottom*cos(0),
  2813. radiusBottom*sin(0),
  2814. -height*0.5));
  2815. bottomface.push(0);
  2816. // First top point
  2817. verts.push(new CANNON.Vec3(radiusTop*cos(0),
  2818. radiusTop*sin(0),
  2819. height*0.5));
  2820. topface.push(1);
  2821. for(var i=0; i<N; i++){
  2822. var theta = 2*Math.PI/N * (i+1);
  2823. var thetaN = 2*Math.PI/N * (i+0.5);
  2824. if(i<N-1){
  2825. // Bottom
  2826. verts.push(new CANNON.Vec3(radiusBottom*cos(theta),
  2827. radiusBottom*sin(theta),
  2828. -height*0.5));
  2829. bottomface.push(2*i+2);
  2830. // Top
  2831. verts.push(new CANNON.Vec3(radiusTop*cos(theta),
  2832. radiusTop*sin(theta),
  2833. height*0.5));
  2834. topface.push(2*i+3);
  2835. // Normal
  2836. normals.push(new CANNON.Vec3(cos(thetaN),
  2837. sin(thetaN),
  2838. 0));
  2839. // Face
  2840. faces.push([2*i+2, 2*i+3, 2*i+1,2*i]);
  2841. } else {
  2842. faces.push([0,1, 2*i+1, 2*i]); // Connect
  2843. // Normal
  2844. normals.push(new CANNON.Vec3(cos(thetaN),sin(thetaN),0));
  2845. }
  2846. }
  2847. faces.push(topface);
  2848. normals.push(new CANNON.Vec3(0,0,1));
  2849. // Reorder bottom face
  2850. var temp = [];
  2851. for(var i=0; i<bottomface.length; i++){
  2852. temp.push(bottomface[bottomface.length - i - 1]);
  2853. }
  2854. faces.push(temp);
  2855. normals.push(new CANNON.Vec3(0,0,-1));
  2856. this.type = CANNON.Shape.types.CONVEXPOLYHEDRON;
  2857. CANNON.ConvexPolyhedron.call( this, verts, faces, normals );
  2858. };
  2859. CANNON.Cylinder.prototype = new CANNON.ConvexPolyhedron();
  2860. /**
  2861. * @class CANNON.Ray
  2862. * @author Originally written by mr.doob / http://mrdoob.com/ for Three.js. Cannon.js-ified by schteppe.
  2863. * @brief A line in 3D space that intersects bodies and return points.
  2864. * @param CANNON.Vec3 origin
  2865. * @param CANNON.Vec3 direction
  2866. */
  2867. CANNON.Ray = function(origin, direction){
  2868. /**
  2869. * @property CANNON.Vec3 origin
  2870. * @memberof CANNON.Ray
  2871. */
  2872. this.origin = origin || new CANNON.Vec3();
  2873. /**
  2874. * @property CANNON.Vec3 direction
  2875. * @memberof CANNON.Ray
  2876. */
  2877. this.direction = direction || new CANNON.Vec3();
  2878. var precision = 0.0001;
  2879. /**
  2880. * @method setPrecision
  2881. * @memberof CANNON.Ray
  2882. * @param float value
  2883. * @brief Sets the precision of the ray. Used when checking parallelity etc.
  2884. */
  2885. this.setPrecision = function ( value ) {
  2886. precision = value;
  2887. };
  2888. var a = new CANNON.Vec3();
  2889. var b = new CANNON.Vec3();
  2890. var c = new CANNON.Vec3();
  2891. var d = new CANNON.Vec3();
  2892. var directionCopy = new CANNON.Vec3();
  2893. var vector = new CANNON.Vec3();
  2894. var normal = new CANNON.Vec3();
  2895. var intersectPoint = new CANNON.Vec3();
  2896. /**
  2897. * @method intersectBody
  2898. * @memberof CANNON.Ray
  2899. * @param CANNON.RigidBody body
  2900. * @brief Shoot a ray at a body, get back information about the hit.
  2901. * @return Array An array of results. The result objects has properties: distance (float), point (CANNON.Vec3) and body (CANNON.RigidBody).
  2902. */
  2903. this.intersectBody = function ( body ) {
  2904. if(body.shape instanceof CANNON.ConvexPolyhedron){
  2905. return this.intersectShape(body.shape,
  2906. body.quaternion,
  2907. body.position,
  2908. body);
  2909. } else if(body.shape instanceof CANNON.Box){
  2910. return this.intersectShape(body.shape.convexPolyhedronRepresentation,
  2911. body.quaternion,
  2912. body.position,
  2913. body);
  2914. } else {
  2915. console.warn("Ray intersection is this far only implemented for ConvexPolyhedron and Box shapes.");
  2916. }
  2917. };
  2918. /**
  2919. * @method intersectShape
  2920. * @memberof CANNON.Ray
  2921. * @param CANNON.Shape shape
  2922. * @param CANNON.Quaternion quat
  2923. * @param CANNON.Vec3 position
  2924. * @param CANNON.RigidBody body
  2925. * @return Array See intersectBody()
  2926. */
  2927. this.intersectShape = function(shape,quat,position,body){
  2928. var intersect, intersects = [];
  2929. if ( shape instanceof CANNON.ConvexPolyhedron ) {
  2930. // Checking boundingSphere
  2931. var distance = distanceFromIntersection( this.origin, this.direction, position );
  2932. if ( distance > shape.getBoundingSphereRadius() ) {
  2933. return intersects;
  2934. }
  2935. // Checking faces
  2936. var dot, scalar, faces = shape.faces, vertices = shape.vertices, normals = shape.faceNormals;
  2937. for (var fi = 0; fi < faces.length; fi++ ) {
  2938. var face = faces[ fi ];
  2939. var faceNormal = normals[ fi ];
  2940. var q = quat;
  2941. var x = position;
  2942. // determine if ray intersects the plane of the face
  2943. // note: this works regardless of the direction of the face normal
  2944. // Get plane point in world coordinates...
  2945. vertices[face[0]].copy(vector);
  2946. q.vmult(vector,vector);
  2947. vector.vadd(x,vector);
  2948. // ...but make it relative to the ray origin. We'll fix this later.
  2949. vector.vsub(this.origin,vector);
  2950. // Get plane normal
  2951. q.vmult(faceNormal,normal);
  2952. // If this dot product is negative, we have something interesting
  2953. dot = this.direction.dot(normal);
  2954. // bail if ray and plane are parallel
  2955. if ( Math.abs( dot ) < precision ){
  2956. continue;
  2957. }
  2958. // calc distance to plane
  2959. scalar = normal.dot( vector ) / dot;
  2960. // if negative distance, then plane is behind ray
  2961. if ( scalar < 0 ){
  2962. continue;
  2963. }
  2964. if ( dot < 0 ) {
  2965. // Intersection point is origin + direction * scalar
  2966. this.direction.mult(scalar,intersectPoint);
  2967. intersectPoint.vadd(this.origin,intersectPoint);
  2968. // a is the point we compare points b and c with.
  2969. vertices[ face[0] ].copy(a);
  2970. q.vmult(a,a);
  2971. x.vadd(a,a);
  2972. for(var i=1; i<face.length-1; i++){
  2973. // Transform 3 vertices to world coords
  2974. vertices[ face[i] ].copy(b);
  2975. vertices[ face[i+1] ].copy(c);
  2976. q.vmult(b,b);
  2977. q.vmult(c,c);
  2978. x.vadd(b,b);
  2979. x.vadd(c,c);
  2980. if ( pointInTriangle( intersectPoint, a, b, c ) ) {
  2981. intersect = {
  2982. distance: this.origin.distanceTo( intersectPoint ),
  2983. point: intersectPoint.copy(),
  2984. face: face,
  2985. body: body
  2986. };
  2987. intersects.push( intersect );
  2988. break;
  2989. }
  2990. }
  2991. }
  2992. }
  2993. }
  2994. return intersects;
  2995. };
  2996. /**
  2997. * @method intersectBodies
  2998. * @memberof CANNON.Ray
  2999. * @param Array bodies An array of CANNON.RigidBody objects.
  3000. * @return Array See intersectBody
  3001. */
  3002. this.intersectBodies = function ( bodies ) {
  3003. var intersects = [];
  3004. for ( var i = 0, l = bodies.length; i < l; i ++ ) {
  3005. var result = this.intersectBody( bodies[ i ] );
  3006. Array.prototype.push.apply( intersects, result );
  3007. }
  3008. intersects.sort( function ( a, b ) { return a.distance - b.distance; } );
  3009. return intersects;
  3010. };
  3011. var v0 = new CANNON.Vec3(), intersect = new CANNON.Vec3();
  3012. var dot, distance;
  3013. function distanceFromIntersection( origin, direction, position ) {
  3014. // v0 is vector from origin to position
  3015. position.vsub(origin,v0);
  3016. dot = v0.dot( direction );
  3017. // intersect = direction*dot + origin
  3018. direction.mult(dot,intersect);
  3019. intersect.vadd(origin,intersect);
  3020. distance = position.distanceTo( intersect );
  3021. return distance;
  3022. }
  3023. // http://www.blackpawn.com/texts/pointinpoly/default.html
  3024. var dot00, dot01, dot02, dot11, dot12, invDenom, u, v;
  3025. var v1 = new CANNON.Vec3(), v2 = new CANNON.Vec3();
  3026. function pointInTriangle( p, a, b, c ) {
  3027. c.vsub(a,v0);
  3028. b.vsub(a,v1);
  3029. p.vsub(a,v2);
  3030. dot00 = v0.dot( v0 );
  3031. dot01 = v0.dot( v1 );
  3032. dot02 = v0.dot( v2 );
  3033. dot11 = v1.dot( v1 );
  3034. dot12 = v1.dot( v2 );
  3035. invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 );
  3036. u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
  3037. v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
  3038. return ( u >= 0 ) && ( v >= 0 ) && ( u + v < 1 );
  3039. }
  3040. };
  3041. CANNON.Ray.prototype.constructor = CANNON.Ray;
  3042. /**
  3043. * @class CANNON.Broadphase
  3044. * @author schteppe
  3045. * @brief Base class for broadphase implementations
  3046. */
  3047. CANNON.Broadphase = function(){
  3048. /**
  3049. * @property CANNON.World world
  3050. * @brief The world to search for collisions in.
  3051. * @memberof CANNON.Broadphase
  3052. */
  3053. this.world = null;
  3054. /**
  3055. * If set to true, the broadphase uses bounding boxes for intersection test, else it uses bounding spheres.
  3056. * @property bool useBoundingBoxes
  3057. * @memberof CANNON.Broadphase
  3058. */
  3059. this.useBoundingBoxes = false;
  3060. };
  3061. CANNON.Broadphase.prototype.constructor = CANNON.BroadPhase;
  3062. /**
  3063. * @method collisionPairs
  3064. * @memberof CANNON.Broadphase
  3065. * @brief Get the collision pairs from the world
  3066. * @param CANNON.World world The world to search in
  3067. * @param Array p1 Empty array to be filled with body objects
  3068. * @param Array p2 Empty array to be filled with body objects
  3069. * @return array An array with two subarrays of body indices
  3070. */
  3071. CANNON.Broadphase.prototype.collisionPairs = function(world,p1,p2){
  3072. throw new Error("collisionPairs not implemented for this BroadPhase class!");
  3073. };
  3074. /**
  3075. * @method needBroadphaseCollision
  3076. * @memberof CANNON.Broadphase
  3077. * @brief Check if a body pair needs to be intersection tested at all.
  3078. * @param CANNON.Body bodyA
  3079. * @param CANNON.Body bodyB
  3080. * @return bool
  3081. */
  3082. var Broadphase_needBroadphaseCollision_STATIC_OR_KINEMATIC = CANNON.Body.STATIC | CANNON.Body.KINEMATIC;
  3083. CANNON.Broadphase.prototype.needBroadphaseCollision = function(bodyA,bodyB){
  3084. // Check collision filter masks
  3085. if( (bodyA.collisionFilterGroup & bodyB.collisionFilterMask)===0 || (bodyB.collisionFilterGroup & bodyA.collisionFilterMask)===0){
  3086. return false;
  3087. }
  3088. // Check motionstate
  3089. if(((bodyA.motionstate & Broadphase_needBroadphaseCollision_STATIC_OR_KINEMATIC)!==0 || bodyA.isSleeping()) &&
  3090. ((bodyB.motionstate & Broadphase_needBroadphaseCollision_STATIC_OR_KINEMATIC)!==0 || bodyB.isSleeping())) {
  3091. // Both bodies are static, kinematic or sleeping. Skip.
  3092. return false;
  3093. }
  3094. // Two particles don't collide
  3095. if(!bodyA.shape && !bodyB.shape){
  3096. return false;
  3097. }
  3098. // Two planes don't collide
  3099. if(bodyA.shape instanceof CANNON.Plane && bodyB.shape instanceof CANNON.Plane){
  3100. return false;
  3101. }
  3102. return true;
  3103. };
  3104. /**
  3105. * @method intersectionTest
  3106. * @memberof CANNON.Broadphase
  3107. * @brief Check if a body pair needs to be intersection tested at all.
  3108. * @param CANNON.Body bodyA
  3109. * @param CANNON.Body bodyB
  3110. * @return bool
  3111. */
  3112. CANNON.Broadphase.prototype.intersectionTest = function(bi,bj,pairs1,pairs2){
  3113. if(this.useBoundingBoxes){
  3114. this.doBoundingBoxBroadphase(bi,bj,pairs1,pairs2);
  3115. } else {
  3116. this.doBoundingSphereBroadphase(bi,bj,pairs1,pairs2);
  3117. }
  3118. };
  3119. /**
  3120. * @method doBoundingSphereBroadphase
  3121. * @memberof CANNON.Broadphase
  3122. * @brief Check if the bounding spheres of two bodies are intersecting.
  3123. * @param CANNON.Body bi
  3124. * @param CANNON.Body bj
  3125. * @param Array pairs1 bi is appended to this array if intersection
  3126. * @param Array pairs2 bj is appended to this array if intersection
  3127. */
  3128. var Broadphase_collisionPairs_r = new CANNON.Vec3(), // Temp objects
  3129. Broadphase_collisionPairs_normal = new CANNON.Vec3(),
  3130. Broadphase_collisionPairs_quat = new CANNON.Quaternion(),
  3131. Broadphase_collisionPairs_relpos = new CANNON.Vec3();
  3132. CANNON.Broadphase.prototype.doBoundingSphereBroadphase = function(bi,bj,pairs1,pairs2){
  3133. // Local fast access
  3134. var types = CANNON.Shape.types,
  3135. BOX_SPHERE_COMPOUND_CONVEX = types.SPHERE | types.BOX | types.COMPOUND | types.CONVEXPOLYHEDRON,
  3136. PLANE = types.PLANE,
  3137. STATIC_OR_KINEMATIC = CANNON.Body.STATIC | CANNON.Body.KINEMATIC;
  3138. // Temp vecs
  3139. var r = Broadphase_collisionPairs_r,
  3140. normal = Broadphase_collisionPairs_normal,
  3141. quat = Broadphase_collisionPairs_quat,
  3142. relpos = Broadphase_collisionPairs_relpos;
  3143. var bishape = bi.shape, bjshape = bj.shape;
  3144. if(bishape && bjshape){
  3145. var ti = bishape.type, tj = bjshape.type;
  3146. // --- Box / sphere / compound / convexpolyhedron collision ---
  3147. if((ti & BOX_SPHERE_COMPOUND_CONVEX) && (tj & BOX_SPHERE_COMPOUND_CONVEX)){
  3148. // Rel. position
  3149. bj.position.vsub(bi.position,r);
  3150. // Update bounding spheres if needed
  3151. if(bishape.boundingSphereRadiusNeedsUpdate){
  3152. bishape.computeBoundingSphereRadius();
  3153. }
  3154. if(bjshape.boundingSphereRadiusNeedsUpdate){
  3155. bjshape.computeBoundingSphereRadius();
  3156. }
  3157. var boundingRadiusSum = bishape.boundingSphereRadius + bjshape.boundingSphereRadius;
  3158. if(r.norm2() < boundingRadiusSum*boundingRadiusSum){
  3159. pairs1.push(bi);
  3160. pairs2.push(bj);
  3161. }
  3162. // --- Sphere/box/compound/convexpoly versus plane ---
  3163. } else if((ti & BOX_SPHERE_COMPOUND_CONVEX) && (tj & types.PLANE) || (tj & BOX_SPHERE_COMPOUND_CONVEX) && (ti & types.PLANE)){
  3164. var planeBody = (ti===PLANE) ? bi : bj, // Plane
  3165. otherBody = (ti!==PLANE) ? bi : bj; // Other
  3166. var otherShape = otherBody.shape;
  3167. var planeShape = planeBody.shape;
  3168. // Rel. position
  3169. otherBody.position.vsub(planeBody.position,r);
  3170. if(planeShape.worldNormalNeedsUpdate){
  3171. planeShape.computeWorldNormal(planeBody.quaternion);
  3172. }
  3173. normal = planeShape.worldNormal;
  3174. if(otherShape.boundingSphereRadiusNeedsUpdate){
  3175. otherShape.computeBoundingSphereRadius();
  3176. }
  3177. var q = r.dot(normal) - otherShape.boundingSphereRadius;
  3178. if(q < 0.0){
  3179. pairs1.push(bi);
  3180. pairs2.push(bj);
  3181. }
  3182. }
  3183. } else {
  3184. // Particle without shape
  3185. if(!bishape && !bjshape){
  3186. // No collisions between 2 particles
  3187. } else {
  3188. var particle = bishape ? bj : bi;
  3189. var other = bishape ? bi : bj;
  3190. var otherShape = other.shape;
  3191. var type = otherShape.type;
  3192. if(type & BOX_SPHERE_COMPOUND_CONVEX){
  3193. if(type === types.SPHERE){ // particle-sphere
  3194. particle.position.vsub(other.position,relpos);
  3195. if(otherShape.radius*otherShape.radius >= relpos.norm2()){
  3196. pairs1.push(particle);
  3197. pairs2.push(other);
  3198. }
  3199. } else if(type===types.CONVEXPOLYHEDRON || type===types.BOX || type===types.COMPOUND){
  3200. if(otherShape.boundingSphereRadiusNeedsUpdate){
  3201. otherShape.computeBoundingSphereRadius();
  3202. }
  3203. var R = otherShape.boundingSphereRadius;
  3204. particle.position.vsub(other.position,relpos);
  3205. if(R*R >= relpos.norm2()){
  3206. pairs1.push(particle);
  3207. pairs2.push(other);
  3208. }
  3209. }
  3210. } else if(type === types.PLANE){
  3211. // particle/plane
  3212. var plane = other;
  3213. normal.set(0,0,1);
  3214. plane.quaternion.vmult(normal,normal);
  3215. particle.position.vsub(plane.position,relpos);
  3216. if(normal.dot(relpos)<=0.0){
  3217. pairs1.push(particle);
  3218. pairs2.push(other);
  3219. }
  3220. }
  3221. }
  3222. }
  3223. };
  3224. /**
  3225. * @method doBoundingBoxBroadphase
  3226. * @memberof CANNON.Broadphase
  3227. * @brief Check if the bounding boxes of two bodies are intersecting.
  3228. * @param CANNON.Body bi
  3229. * @param CANNON.Body bj
  3230. * @param Array pairs1
  3231. * @param Array pairs2
  3232. */
  3233. CANNON.Broadphase.prototype.doBoundingBoxBroadphase = function(bi,bj,pairs1,pairs2){
  3234. var bishape = bi.shape,
  3235. bjshape = bj.shape;
  3236. if(bi.aabbNeedsUpdate){
  3237. bi.computeAABB();
  3238. }
  3239. if(bj.aabbNeedsUpdate){
  3240. bj.computeAABB();
  3241. }
  3242. if(bishape && bjshape){
  3243. // Check AABB / AABB
  3244. if( !( bi.aabbmax.x < bj.aabbmin.x ||
  3245. bi.aabbmax.y < bj.aabbmin.y ||
  3246. bi.aabbmax.z < bj.aabbmin.z ||
  3247. bi.aabbmin.x > bj.aabbmax.x ||
  3248. bi.aabbmin.y > bj.aabbmax.y ||
  3249. bi.aabbmin.z > bj.aabbmax.z ) ){
  3250. pairs1.push(bi);
  3251. pairs2.push(bj);
  3252. }
  3253. } else {
  3254. // Particle without shape
  3255. if(!bishape && !bjshape){
  3256. // No collisions between 2 particles
  3257. } else {
  3258. // particle vs AABB
  3259. var p = !bishape ? bi : bj;
  3260. var other = !bishape ? bj : bi;
  3261. if(other.shape instanceof CANNON.Plane){
  3262. //console.log(p.position.z+"<"+other.aabbmin.z+" = ",p.position.z < other.aabbmin.z);
  3263. }
  3264. if( !( p.position.x < other.aabbmin.x ||
  3265. p.position.y < other.aabbmin.y ||
  3266. p.position.z < other.aabbmin.z ||
  3267. p.position.x > other.aabbmax.x ||
  3268. p.position.y > other.aabbmax.y ||
  3269. p.position.z > other.aabbmax.z ) ){
  3270. pairs1.push(bi);
  3271. pairs2.push(bj);
  3272. }
  3273. }
  3274. }
  3275. };
  3276. /**
  3277. * @method makePairsUnique
  3278. * @memberof CANNON.Broadphase
  3279. * @brief Removes duplicate pairs from the pair arrays.
  3280. * @param Array pairs1
  3281. * @param Array pairs2
  3282. */
  3283. var Broadphase_makePairsUnique_temp = {},
  3284. Broadphase_makePairsUnique_p1 = [],
  3285. Broadphase_makePairsUnique_p2 = [];
  3286. CANNON.Broadphase.prototype.makePairsUnique = function(pairs1,pairs2){
  3287. var t = Broadphase_makePairsUnique_temp,
  3288. p1 = Broadphase_makePairsUnique_p1,
  3289. p2 = Broadphase_makePairsUnique_p2,
  3290. N = pairs1.length;
  3291. for(var i=0; i!==N; i++){
  3292. p1[i] = pairs1[i];
  3293. p2[i] = pairs2[i];
  3294. }
  3295. pairs1.length = 0;
  3296. pairs2.length = 0;
  3297. for(var i=0; i!==N; i++){
  3298. var id1 = p1[i].id,
  3299. id2 = p2[i].id;
  3300. var idx = id1 < id2 ? id1+","+id2 : id2+","+id1;
  3301. t[idx] = i;
  3302. }
  3303. for(var idx in t){
  3304. var i = t[idx];
  3305. pairs1.push(p1[i]);
  3306. pairs2.push(p2[i]);
  3307. delete t[idx];
  3308. }
  3309. };
  3310. /**
  3311. * @class CANNON.NaiveBroadphase
  3312. * @brief Naive broadphase implementation, used in lack of better ones.
  3313. * @description The naive broadphase looks at all possible pairs without restriction, therefore it has complexity N^2 (which is bad)
  3314. * @extends CANNON.Broadphase
  3315. */
  3316. CANNON.NaiveBroadphase = function(){
  3317. CANNON.Broadphase.apply(this);
  3318. };
  3319. CANNON.NaiveBroadphase.prototype = new CANNON.Broadphase();
  3320. CANNON.NaiveBroadphase.prototype.constructor = CANNON.NaiveBroadphase;
  3321. /**
  3322. * @method collisionPairs
  3323. * @memberof CANNON.NaiveBroadphase
  3324. * @brief Get all the collision pairs in the physics world
  3325. * @param CANNON.World world
  3326. * @param Array pairs1
  3327. * @param Array pairs2
  3328. */
  3329. CANNON.NaiveBroadphase.prototype.collisionPairs = function(world,pairs1,pairs2){
  3330. var bodies = world.bodies,
  3331. n = bodies.length,
  3332. i,j,bi,bj;
  3333. // Naive N^2 ftw!
  3334. for(i=0; i!==n; i++){
  3335. for(j=0; j!==i; j++){
  3336. bi = bodies[i];
  3337. bj = bodies[j];
  3338. if(!this.needBroadphaseCollision(bi,bj)){
  3339. continue;
  3340. }
  3341. this.intersectionTest(bi,bj,pairs1,pairs2);
  3342. }
  3343. }
  3344. };
  3345. /**
  3346. * @class CANNON.GridBroadphase
  3347. * @brief Axis aligned uniform grid broadphase.
  3348. * @extends CANNON.Broadphase
  3349. * @todo Needs support for more than just planes and spheres.
  3350. * @param CANNON.Vec3 aabbMin
  3351. * @param CANNON.Vec3 aabbMax
  3352. * @param int nx Number of boxes along x
  3353. * @param int ny Number of boxes along y
  3354. * @param int nz Number of boxes along z
  3355. */
  3356. CANNON.GridBroadphase = function(aabbMin,aabbMax,nx,ny,nz){
  3357. CANNON.Broadphase.apply(this);
  3358. this.nx = nx || 10;
  3359. this.ny = ny || 10;
  3360. this.nz = nz || 10;
  3361. this.aabbMin = aabbMin || new CANNON.Vec3(100,100,100);
  3362. this.aabbMax = aabbMax || new CANNON.Vec3(-100,-100,-100);
  3363. this.bins = [];
  3364. };
  3365. CANNON.GridBroadphase.prototype = new CANNON.Broadphase();
  3366. CANNON.GridBroadphase.prototype.constructor = CANNON.GridBroadphase;
  3367. /**
  3368. * @method collisionPairs
  3369. * @memberof CANNON.GridBroadphase
  3370. * @brief Get all the collision pairs in the physics world
  3371. * @param CANNON.World world
  3372. * @param Array pairs1
  3373. * @param Array pairs2
  3374. */
  3375. var GridBroadphase_collisionPairs_d = new CANNON.Vec3();
  3376. var GridBroadphase_collisionPairs_binPos = new CANNON.Vec3();
  3377. CANNON.GridBroadphase.prototype.collisionPairs = function(world,pairs1,pairs2){
  3378. var N = world.numObjects(),
  3379. bodies = world.bodies;
  3380. var max = this.aabbMax,
  3381. min = this.aabbMin,
  3382. nx = this.nx,
  3383. ny = this.ny,
  3384. nz = this.nz;
  3385. var xmax = max.x,
  3386. ymax = max.y,
  3387. zmax = max.z,
  3388. xmin = min.x,
  3389. ymin = min.y,
  3390. zmin = min.z;
  3391. var xmult = nx / (xmax-xmin),
  3392. ymult = ny / (ymax-ymin),
  3393. zmult = nz / (zmax-zmin);
  3394. var binsizeX = (xmax - xmin) / nx,
  3395. binsizeY = (ymax - ymin) / ny,
  3396. binsizeZ = (zmax - zmin) / nz;
  3397. var types = CANNON.Shape.types;
  3398. var SPHERE = types.SPHERE,
  3399. PLANE = types.PLANE,
  3400. BOX = types.BOX,
  3401. COMPOUND = types.COMPOUND,
  3402. CONVEXPOLYHEDRON = types.CONVEXPOLYHEDRON;
  3403. var bins=this.bins,
  3404. Nbins=nx*ny*nz;
  3405. // Reset bins
  3406. for(var i=bins.length-1; i!==Nbins; i++){
  3407. bins.push([]);
  3408. }
  3409. for(var i=0; i!==Nbins; i++){
  3410. bins[i].length = 0;
  3411. }
  3412. var floor = Math.floor;
  3413. // Put all bodies into the bins
  3414. for(var i=0; i!==N; i++){
  3415. var bi = bodies[i];
  3416. var si = bi.shape;
  3417. switch(si.type){
  3418. case SPHERE:
  3419. // Put in bin
  3420. // check if overlap with other bins
  3421. var x = bi.position.x,
  3422. y = bi.position.y,
  3423. z = bi.position.z;
  3424. var r = si.radius;
  3425. var xi1 = floor(xmult * (x-r - xmin)),
  3426. yi1 = floor(ymult * (y-r - ymin)),
  3427. zi1 = floor(zmult * (z-r - zmin)),
  3428. xi2 = floor(xmult * (x+r - xmin)),
  3429. yi2 = floor(ymult * (y+r - ymin)),
  3430. zi2 = floor(zmult * (z+r - zmin));
  3431. for(var j=xi1; j!==xi2+1; j++){
  3432. for(var k=yi1; k!==yi2+1; k++){
  3433. for(var l=zi1; l!==zi2+1; l++){
  3434. var xi = j,
  3435. yi = k,
  3436. zi = l;
  3437. var idx = xi * ( ny - 1 ) * ( nz - 1 ) + yi * ( nz - 1 ) + zi;
  3438. if(idx >= 0 && idx < Nbins){
  3439. bins[ idx ].push( bi );
  3440. }
  3441. }
  3442. }
  3443. }
  3444. break;
  3445. case PLANE:
  3446. // Put in all bins for now
  3447. // @todo put only in bins that are actually intersecting the plane
  3448. var d = GridBroadphase_collisionPairs_d;
  3449. var binPos = GridBroadphase_collisionPairs_binPos;
  3450. var binRadiusSquared = (binsizeX*binsizeX + binsizeY*binsizeY + binsizeZ*binsizeZ) * 0.25;
  3451. var planeNormal = si.worldNormal;
  3452. if(si.worldNormalNeedsUpdate){
  3453. si.computeWorldNormal(bi.quaternion);
  3454. }
  3455. for(var j=0; j!==nx; j++){
  3456. for(var k=0; k!==ny; k++){
  3457. for(var l=0; l!==nz; l++){
  3458. var xi = j,
  3459. yi = k,
  3460. zi = l;
  3461. binPos.set(xi*binsizeX+xmin, yi*binsizeY+ymin, zi*binsizeZ+zmin);
  3462. binPos.vsub(bi.position, d);
  3463. if(d.dot(planeNormal) < binRadiusSquared){
  3464. var idx = xi * ( ny - 1 ) * ( nz - 1 ) + yi * ( nz - 1 ) + zi;
  3465. bins[ idx ].push( bi );
  3466. }
  3467. }
  3468. }
  3469. }
  3470. break;
  3471. default:
  3472. console.warn("Shape "+si.type+" not supported in GridBroadphase!");
  3473. break;
  3474. }
  3475. }
  3476. // Check each bin
  3477. for(var i=0; i!==Nbins; i++){
  3478. var bin = bins[i];
  3479. // Do N^2 broadphase inside
  3480. for(var j=0, NbodiesInBin=bin.length; j!==NbodiesInBin; j++){
  3481. var bi = bin[j];
  3482. for(var k=0; k!==j; k++){
  3483. var bj = bin[k];
  3484. if(this.needBroadphaseCollision(bi,bj)){
  3485. this.intersectionTest(bi,bj,pairs1,pairs2);
  3486. }
  3487. }
  3488. }
  3489. }
  3490. this.makePairsUnique(pairs1,pairs2);
  3491. };
  3492. /**
  3493. * @class CANNON.Solver
  3494. * @brief Constraint equation solver base class.
  3495. * @author schteppe / https://github.com/schteppe
  3496. */
  3497. CANNON.Solver = function(){
  3498. // All equations to be solved
  3499. this.equations = [];
  3500. };
  3501. // Should be implemented in subclasses!
  3502. CANNON.Solver.prototype.solve = function(dt,world){
  3503. // Should return the number of iterations done!
  3504. return 0;
  3505. };
  3506. CANNON.Solver.prototype.addEquation = function(eq){
  3507. this.equations.push(eq);
  3508. };
  3509. CANNON.Solver.prototype.removeEquation = function(eq){
  3510. var eqs = this.equations;
  3511. var i = eqs.indexOf(eq);
  3512. if(i !== -1){
  3513. eqs.splice(i,1);
  3514. }
  3515. };
  3516. CANNON.Solver.prototype.removeAllEquations = function(){
  3517. this.equations.length = 0;
  3518. };
  3519. /**
  3520. * @class CANNON.Solver
  3521. * @brief Constraint equation Gauss-Seidel solver.
  3522. * @todo The spook parameters should be specified for each constraint, not globally.
  3523. * @author schteppe / https://github.com/schteppe
  3524. * @see https://www8.cs.umu.se/kurser/5DV058/VT09/lectures/spooknotes.pdf
  3525. * @extends CANNON.Solver
  3526. */
  3527. CANNON.GSSolver = function(){
  3528. CANNON.Solver.call(this);
  3529. /**
  3530. * @property int iterations
  3531. * @brief 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.
  3532. * @todo write more about solver and iterations in the wiki
  3533. * @memberof CANNON.GSSolver
  3534. */
  3535. this.iterations = 10;
  3536. /**
  3537. * When tolerance is reached, the system is assumed to be converged.
  3538. * @property float tolerance
  3539. */
  3540. this.tolerance = 0;
  3541. };
  3542. CANNON.GSSolver.prototype = new CANNON.Solver();
  3543. var GSSolver_solve_lambda = []; // Just temporary number holders that we want to reuse each solve.
  3544. var GSSolver_solve_invCs = [];
  3545. var GSSolver_solve_Bs = [];
  3546. CANNON.GSSolver.prototype.solve = function(dt,world){
  3547. var d = this.d,
  3548. ks = this.k,
  3549. iter = 0,
  3550. maxIter = this.iterations,
  3551. tolSquared = this.tolerance*this.tolerance,
  3552. a = this.a,
  3553. b = this.b,
  3554. equations = this.equations,
  3555. Neq = equations.length,
  3556. bodies = world.bodies,
  3557. Nbodies = bodies.length,
  3558. h = dt,
  3559. q, B, invC, deltalambda, deltalambdaTot, GWlambda, lambdaj;
  3560. // Things that does not change during iteration can be computed once
  3561. var invCs = GSSolver_solve_invCs,
  3562. Bs = GSSolver_solve_Bs,
  3563. lambda = GSSolver_solve_lambda;
  3564. invCs.length = 0;
  3565. Bs.length = 0;
  3566. lambda.length = 0;
  3567. for(var i=0; i!==Neq; i++){
  3568. var c = equations[i];
  3569. if(c.spookParamsNeedsUpdate){
  3570. c.updateSpookParams(h);
  3571. c.spookParamsNeedsUpdate = false;
  3572. }
  3573. lambda[i] = 0.0;
  3574. Bs[i] = c.computeB(h);
  3575. invCs[i] = 1.0 / c.computeC();
  3576. }
  3577. if(Neq !== 0){
  3578. // Reset vlambda
  3579. for(var i=0; i!==Nbodies; i++){
  3580. var b=bodies[i],
  3581. vlambda=b.vlambda,
  3582. wlambda=b.wlambda;
  3583. vlambda.set(0,0,0);
  3584. if(wlambda){
  3585. wlambda.set(0,0,0);
  3586. }
  3587. }
  3588. // Iterate over equations
  3589. for(iter=0; iter!==maxIter; iter++){
  3590. // Accumulate the total error for each iteration.
  3591. deltalambdaTot = 0.0;
  3592. for(var j=0; j!==Neq; j++){
  3593. var c = equations[j];
  3594. // Compute iteration
  3595. B = Bs[j];
  3596. invC = invCs[j];
  3597. lambdaj = lambda[j];
  3598. GWlambda = c.computeGWlambda();
  3599. deltalambda = invC * ( B - GWlambda - c.eps * lambdaj );
  3600. // Clamp if we are not within the min/max interval
  3601. if(lambdaj + deltalambda < c.minForce){
  3602. deltalambda = c.minForce - lambdaj;
  3603. } else if(lambdaj + deltalambda > c.maxForce){
  3604. deltalambda = c.maxForce - lambdaj;
  3605. }
  3606. lambda[j] += deltalambda;
  3607. deltalambdaTot += deltalambda > 0.0 ? deltalambda : -deltalambda; // abs(deltalambda)
  3608. c.addToWlambda(deltalambda);
  3609. }
  3610. // If the total error is small enough - stop iterate
  3611. if(deltalambdaTot*deltalambdaTot < tolSquared){
  3612. break;
  3613. }
  3614. }
  3615. // Add result to velocity
  3616. for(var i=0; i!==Nbodies; i++){
  3617. var b=bodies[i],
  3618. v=b.velocity,
  3619. w=b.angularVelocity;
  3620. v.vadd(b.vlambda, v);
  3621. if(w){
  3622. w.vadd(b.wlambda, w);
  3623. }
  3624. }
  3625. }
  3626. return iter;
  3627. };
  3628. CANNON.SplitSolver = function(subsolver){
  3629. CANNON.Solver.call(this);
  3630. this.subsolver = subsolver;
  3631. };
  3632. CANNON.SplitSolver.prototype = new CANNON.Solver();
  3633. // Returns the number of subsystems
  3634. var SplitSolver_solve_nodes = []; // All allocated node objects
  3635. var SplitSolver_solve_eqs = []; // Temp array
  3636. var SplitSolver_solve_bds = []; // Temp array
  3637. var SplitSolver_solve_dummyWorld = {bodies:null}; // Temp object
  3638. CANNON.SplitSolver.prototype.solve = function(dt,world){
  3639. var nodes=SplitSolver_solve_nodes,
  3640. bodies=world.bodies,
  3641. equations=this.equations,
  3642. Neq=equations.length,
  3643. Nbodies=bodies.length,
  3644. subsolver=this.subsolver;
  3645. // Create needed nodes, reuse if possible
  3646. for(var i=nodes.length; i!==Nbodies; i++){
  3647. nodes.push({ body:bodies[i], children:[], eqs:[], visited:false });
  3648. }
  3649. // Reset node values
  3650. for(var i=0; i!==Nbodies; i++){
  3651. var node = nodes[i];
  3652. node.body = bodies[i];
  3653. node.children.length = 0;
  3654. node.eqs.length = 0;
  3655. node.visited = false;
  3656. }
  3657. for(var k=0; k!==Neq; k++){
  3658. var eq=equations[k],
  3659. i=bodies.indexOf(eq.bi),
  3660. j=bodies.indexOf(eq.bj),
  3661. ni=nodes[i],
  3662. nj=nodes[j];
  3663. ni.children.push(nj);
  3664. ni.eqs.push(eq);
  3665. nj.children.push(ni);
  3666. nj.eqs.push(eq);
  3667. }
  3668. var STATIC = CANNON.Body.STATIC;
  3669. function getUnvisitedNode(nodes){
  3670. var Nnodes = nodes.length;
  3671. for(var i=0; i!==Nnodes; i++){
  3672. var node = nodes[i];
  3673. if(!node.visited && !(node.body.motionstate & STATIC)){
  3674. return node;
  3675. }
  3676. }
  3677. return false;
  3678. }
  3679. function bfs(root,visitFunc){
  3680. var queue = [];
  3681. queue.push(root);
  3682. root.visited = true;
  3683. visitFunc(root);
  3684. while(queue.length) {
  3685. var node = queue.pop();
  3686. // Loop over unvisited child nodes
  3687. var child;
  3688. while((child = getUnvisitedNode(node.children))) {
  3689. child.visited = true;
  3690. visitFunc(child);
  3691. queue.push(child);
  3692. }
  3693. }
  3694. }
  3695. var child, n=0, eqs=SplitSolver_solve_eqs, bds=SplitSolver_solve_bds;
  3696. function visitFunc(node){
  3697. bds.push(node.body);
  3698. var Neqs = node.eqs.length;
  3699. for(var i=0; i!==Neqs; i++){
  3700. var eq = node.eqs[i];
  3701. if(eqs.indexOf(eq) === -1){
  3702. eqs.push(eq);
  3703. }
  3704. }
  3705. }
  3706. var dummyWorld = SplitSolver_solve_dummyWorld;
  3707. while((child = getUnvisitedNode(nodes))){
  3708. eqs.length = 0;
  3709. bds.length = 0;
  3710. bfs(child,visitFunc);
  3711. var Neqs = eqs.length;
  3712. for(var i=0; i!==Neqs; i++){
  3713. subsolver.addEquation(eqs[i]);
  3714. }
  3715. dummyWorld.bodies = bds;
  3716. var iter = subsolver.solve(dt,dummyWorld);
  3717. subsolver.removeAllEquations();
  3718. n++;
  3719. }
  3720. return n;
  3721. };
  3722. /**
  3723. * @class CANNON.Material
  3724. * @brief Defines a physics material.
  3725. * @param string name
  3726. * @author schteppe
  3727. */
  3728. CANNON.Material = function(name){
  3729. /**
  3730. * @property string name
  3731. * @memberof CANNON.Material
  3732. */
  3733. this.name = name;
  3734. this.id = -1;
  3735. };
  3736. /**
  3737. * @class CANNON.ContactMaterial
  3738. * @brief Defines what happens when two materials meet.
  3739. * @param CANNON.Material m1
  3740. * @param CANNON.Material m2
  3741. * @param float friction
  3742. * @param float restitution
  3743. * @todo Contact solving parameters here too?
  3744. */
  3745. CANNON.ContactMaterial = function(m1, m2, friction, restitution){
  3746. /// Contact material index in the world, -1 until added to the world
  3747. this.id = -1;
  3748. /// The two materials participating in the contact
  3749. this.materials = [m1,m2];
  3750. /// Kinetic friction
  3751. this.friction = friction!==undefined ? Number(friction) : 0.3;
  3752. /// Restitution
  3753. this.restitution = restitution !== undefined ? Number(restitution) : 0.3;
  3754. // Parameters to pass to the constraint when it is created
  3755. this.contactEquationStiffness = 1e7;
  3756. this.contactEquationRegularizationTime = 3;
  3757. this.frictionEquationStiffness = 1e7;
  3758. this.frictionEquationRegularizationTime = 3;
  3759. };
  3760. /**
  3761. * @class CANNON.World
  3762. * @brief The physics world
  3763. */
  3764. CANNON.World = function(){
  3765. CANNON.EventTarget.apply(this);
  3766. /**
  3767. * @property bool allowSleep
  3768. * @brief Makes bodies go to sleep when they've been inactive
  3769. * @memberof CANNON.World
  3770. */
  3771. this.allowSleep = false;
  3772. /**
  3773. * @property Array contacts
  3774. * @brief All the current contacts (instances of CANNON.ContactEquation) in the world.
  3775. * @memberof CANNON.World
  3776. */
  3777. this.contacts = [];
  3778. this.frictionEquations = [];
  3779. /**
  3780. * @property int quatNormalizeSkip
  3781. * @brief 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).
  3782. * @memberof CANNON.World
  3783. */
  3784. this.quatNormalizeSkip = 0;
  3785. /**
  3786. * @property bool quatNormalizeFast
  3787. * @brief Set to true to use fast quaternion normalization. It is often enough accurate to use. If bodies tend to explode, set to false.
  3788. * @memberof CANNON.World
  3789. * @see CANNON.Quaternion.normalizeFast
  3790. * @see CANNON.Quaternion.normalize
  3791. */
  3792. this.quatNormalizeFast = false;
  3793. /**
  3794. * @property float time
  3795. * @brief The wall-clock time since simulation start
  3796. * @memberof CANNON.World
  3797. */
  3798. this.time = 0.0;
  3799. /**
  3800. * @property int stepnumber
  3801. * @brief Number of timesteps taken since start
  3802. * @memberof CANNON.World
  3803. */
  3804. this.stepnumber = 0;
  3805. /// Default and last timestep sizes
  3806. this.default_dt = 1/60;
  3807. this.last_dt = this.default_dt;
  3808. this.nextId = 0;
  3809. /**
  3810. * @property CANNON.Vec3 gravity
  3811. * @memberof CANNON.World
  3812. */
  3813. this.gravity = new CANNON.Vec3();
  3814. /**
  3815. * @property CANNON.Broadphase broadphase
  3816. * @memberof CANNON.World
  3817. */
  3818. this.broadphase = null;
  3819. /**
  3820. * @property Array bodies
  3821. * @memberof CANNON.World
  3822. */
  3823. this.bodies = [];
  3824. var th = this;
  3825. /**
  3826. * @property CANNON.Solver solver
  3827. * @memberof CANNON.World
  3828. */
  3829. this.solver = new CANNON.GSSolver();
  3830. /**
  3831. * @property Array constraints
  3832. * @memberof CANNON.World
  3833. */
  3834. this.constraints = [];
  3835. /**
  3836. * @property CANNON.ContactGenerator contactgen
  3837. * @memberof CANNON.World
  3838. */
  3839. this.contactgen = new CANNON.ContactGenerator();
  3840. /** @property Collision "matrix", size (Nbodies * (Nbodies.length + 1))/2
  3841. * @brief It's actually a triangular-shaped array of whether two bodies are touching this step, for reference next step
  3842. * @memberof CANNON.World
  3843. */
  3844. this.collisionMatrix = [];
  3845. /** @property Collision "matrix", size (Nbodies * (Nbodies.length + 1))/2
  3846. * @brief collisionMatrix from the previous step
  3847. * @memberof CANNON.World
  3848. */
  3849. this.collisionMatrixPrevious = [];
  3850. /**
  3851. * @property Array materials
  3852. * @memberof CANNON.World
  3853. */
  3854. this.materials = []; // References to all added materials
  3855. /**
  3856. * @property Array contactmaterials
  3857. * @memberof CANNON.World
  3858. */
  3859. this.contactmaterials = []; // All added contact materials
  3860. this.mats2cmat = []; // Hash: (mat1_id, mat2_id) => contactmat_id
  3861. this.defaultMaterial = new CANNON.Material("default");
  3862. /**
  3863. * @property CANNON.ContactMaterial defaultContactMaterial
  3864. * @brief This contact material is used if no suitable contactmaterial is found for a contact.
  3865. * @memberof CANNON.World
  3866. */
  3867. this.defaultContactMaterial = new CANNON.ContactMaterial(this.defaultMaterial,this.defaultMaterial,0.3,0.0);
  3868. /**
  3869. * @property bool doProfiling
  3870. * @memberof CANNON.World
  3871. */
  3872. this.doProfiling = false;
  3873. /**
  3874. * @property Object profile
  3875. * @memberof CANNON.World
  3876. */
  3877. this.profile = {
  3878. solve:0,
  3879. makeContactConstraints:0,
  3880. broadphase:0,
  3881. integrate:0,
  3882. nearphase:0,
  3883. };
  3884. /**
  3885. * @property Array subystems
  3886. * @memberof CANNON.World
  3887. */
  3888. this.subsystems = [];
  3889. };
  3890. /**
  3891. * @method getContactMaterial
  3892. * @memberof CANNON.World
  3893. * @brief Get the contact material between materials m1 and m2
  3894. * @param CANNON.Material m1
  3895. * @param CANNON.Material m2
  3896. * @return CANNON.Contactmaterial The contact material if it was found.
  3897. */
  3898. CANNON.World.prototype.getContactMaterial = function(m1,m2){
  3899. if((m1 instanceof CANNON.Material) && (m2 instanceof CANNON.Material)){
  3900. var i = m1.id;
  3901. var j = m2.id;
  3902. if(i<j){
  3903. var temp = i;
  3904. i = j;
  3905. j = temp;
  3906. }
  3907. return this.contactmaterials[this.mats2cmat[i+j*this.materials.length]];
  3908. }
  3909. };
  3910. /**
  3911. * @method numObjects
  3912. * @memberof CANNON.World
  3913. * @brief Get number of objects in the world.
  3914. * @return int
  3915. */
  3916. CANNON.World.prototype.numObjects = function(){
  3917. return this.bodies.length;
  3918. };
  3919. // Keep track of contacts for current and previous timestep
  3920. // 0: No contact between i and j
  3921. // 1: Contact
  3922. CANNON.World.prototype.collisionMatrixGet = function(i,j,current){
  3923. if(j > i){
  3924. var temp = j;
  3925. j = i;
  3926. i = temp;
  3927. }
  3928. // Reuse i for the index
  3929. i = (i*(i + 1)>>1) + j-1;
  3930. return (typeof(current)==="undefined" || current) ? this.collisionMatrix[i] : this.collisionMatrixPrevious[i];
  3931. };
  3932. CANNON.World.prototype.collisionMatrixSet = function(i,j,value,current){
  3933. if(j > i){
  3934. var temp = j;
  3935. j = i;
  3936. i = temp;
  3937. }
  3938. // Reuse i for the index
  3939. i = (i*(i + 1)>>1) + j-1;
  3940. if (typeof(current)==="undefined" || current) {
  3941. this.collisionMatrix[i] = value;
  3942. }
  3943. else {
  3944. this.collisionMatrixPrevious[i] = value;
  3945. }
  3946. };
  3947. // transfer old contact state data to T-1
  3948. CANNON.World.prototype.collisionMatrixTick = function(){
  3949. var temp = this.collisionMatrixPrevious;
  3950. this.collisionMatrixPrevious = this.collisionMatrix;
  3951. this.collisionMatrix = temp;
  3952. for (var i=0,l=this.collisionMatrix.length;i!==l;i++) {
  3953. this.collisionMatrix[i]=0;
  3954. }
  3955. };
  3956. /**
  3957. * @method add
  3958. * @memberof CANNON.World
  3959. * @brief Add a rigid body to the simulation.
  3960. * @param CANNON.Body body
  3961. * @todo If the simulation has not yet started, why recrete and copy arrays for each body? Accumulate in dynamic arrays in this case.
  3962. * @todo Adding an array of bodies should be possible. This would save some loops too
  3963. */
  3964. CANNON.World.prototype.add = function(body){
  3965. body.id = this.id();
  3966. body.index = this.bodies.length;
  3967. this.bodies.push(body);
  3968. body.world = this;
  3969. body.position.copy(body.initPosition);
  3970. body.velocity.copy(body.initVelocity);
  3971. body.timeLastSleepy = this.time;
  3972. if(body instanceof CANNON.RigidBody){
  3973. body.angularVelocity.copy(body.initAngularVelocity);
  3974. body.quaternion.copy(body.initQuaternion);
  3975. }
  3976. var n = this.numObjects();
  3977. this.collisionMatrix.length = n*(n-1)>>1;
  3978. };
  3979. /**
  3980. * @method addConstraint
  3981. * @memberof CANNON.World
  3982. * @brief Add a constraint to the simulation.
  3983. * @param CANNON.Constraint c
  3984. */
  3985. CANNON.World.prototype.addConstraint = function(c){
  3986. this.constraints.push(c);
  3987. c.id = this.id();
  3988. };
  3989. /**
  3990. * @method removeConstraint
  3991. * @memberof CANNON.World
  3992. * @brief Removes a constraint
  3993. * @param CANNON.Constraint c
  3994. */
  3995. CANNON.World.prototype.removeConstraint = function(c){
  3996. var idx = this.constraints.indexOf(c);
  3997. if(idx!==-1){
  3998. this.constraints.splice(idx,1);
  3999. }
  4000. };
  4001. /**
  4002. * @method id
  4003. * @memberof CANNON.World
  4004. * @brief Generate a new unique integer identifyer
  4005. * @return int
  4006. */
  4007. CANNON.World.prototype.id = function(){
  4008. return this.nextId++;
  4009. };
  4010. /**
  4011. * @method remove
  4012. * @memberof CANNON.World
  4013. * @brief Remove a rigid body from the simulation.
  4014. * @param CANNON.Body body
  4015. */
  4016. CANNON.World.prototype.remove = function(body){
  4017. body.world = null;
  4018. var n = this.numObjects()-1;
  4019. var bodies = this.bodies;
  4020. bodies.splice(body.index, 1);
  4021. for(var i=body.index; i<n;i++) {
  4022. bodies[i].index=i;
  4023. }
  4024. //TODO: Maybe splice out the correct elements?
  4025. this.collisionMatrixPrevious.length =
  4026. this.collisionMatrix.length = n*(n-1)>>1;
  4027. };
  4028. /**
  4029. * @method addMaterial
  4030. * @memberof CANNON.World
  4031. * @brief Adds a material to the World. A material can only be added once, it's added more times then nothing will happen.
  4032. * @param CANNON.Material m
  4033. */
  4034. CANNON.World.prototype.addMaterial = function(m){
  4035. if(m.id === -1){
  4036. var n = this.materials.length;
  4037. this.materials.push(m);
  4038. m.id = this.materials.length-1;
  4039. // Increase size of collision matrix to (n+1)*(n+1)=n*n+2*n+1 elements, it was n*n last.
  4040. for(var i=0; i!==2*n+1; i++){
  4041. this.mats2cmat.push(-1);
  4042. }
  4043. }
  4044. };
  4045. /**
  4046. * @method addContactMaterial
  4047. * @memberof CANNON.World
  4048. * @brief Adds a contact material to the World
  4049. * @param CANNON.ContactMaterial cmat
  4050. */
  4051. CANNON.World.prototype.addContactMaterial = function(cmat) {
  4052. // Add materials if they aren't already added
  4053. this.addMaterial(cmat.materials[0]);
  4054. this.addMaterial(cmat.materials[1]);
  4055. // Save (material1,material2) -> (contact material) reference for easy access later
  4056. // Make sure i>j, ie upper right matrix
  4057. var i,j;
  4058. if(cmat.materials[0].id > cmat.materials[1].id){
  4059. i = cmat.materials[0].id;
  4060. j = cmat.materials[1].id;
  4061. } else {
  4062. j = cmat.materials[0].id;
  4063. i = cmat.materials[1].id;
  4064. }
  4065. // Add contact material
  4066. this.contactmaterials.push(cmat);
  4067. cmat.id = this.contactmaterials.length-1;
  4068. // Add current contact material to the material table
  4069. this.mats2cmat[i+this.materials.length*j] = cmat.id; // index of the contact material
  4070. };
  4071. CANNON.World.prototype._now = function(){
  4072. if(window.performance.webkitNow){
  4073. return window.performance.webkitNow();
  4074. } else {
  4075. return Date.now();
  4076. }
  4077. };
  4078. /**
  4079. * @method step
  4080. * @memberof CANNON.World
  4081. * @brief Step the simulation
  4082. * @param float dt
  4083. */
  4084. var World_step_postStepEvent = {type:"postStep"}, // Reusable event objects to save memory
  4085. World_step_preStepEvent = {type:"preStep"},
  4086. World_step_collideEvent = {type:"collide", "with":null, contact:null },
  4087. World_step_oldContacts = [], // Pools for unused objects
  4088. World_step_frictionEquationPool = [],
  4089. World_step_p1 = [], // Reusable arrays for collision pairs
  4090. World_step_p2 = [],
  4091. World_step_gvec = new CANNON.Vec3(), // Temporary vectors and quats
  4092. World_step_vi = new CANNON.Vec3(),
  4093. World_step_vj = new CANNON.Vec3(),
  4094. World_step_wi = new CANNON.Vec3(),
  4095. World_step_wj = new CANNON.Vec3(),
  4096. World_step_t1 = new CANNON.Vec3(),
  4097. World_step_t2 = new CANNON.Vec3(),
  4098. World_step_rixn = new CANNON.Vec3(),
  4099. World_step_rjxn = new CANNON.Vec3(),
  4100. World_step_step_q = new CANNON.Quaternion(),
  4101. World_step_step_w = new CANNON.Quaternion(),
  4102. World_step_step_wq = new CANNON.Quaternion();
  4103. CANNON.World.prototype.step = function(dt){
  4104. var world = this,
  4105. that = this,
  4106. contacts = this.contacts,
  4107. p1 = World_step_p1,
  4108. p2 = World_step_p2,
  4109. N = this.numObjects(),
  4110. bodies = this.bodies,
  4111. solver = this.solver,
  4112. gravity = this.gravity,
  4113. doProfiling = this.doProfiling,
  4114. profile = this.profile,
  4115. DYNAMIC = CANNON.Body.DYNAMIC,
  4116. now = this._now,
  4117. profilingStart,
  4118. constraints = this.constraints,
  4119. FrictionEquation = CANNON.FrictionEquation,
  4120. frictionEquationPool = World_step_frictionEquationPool,
  4121. gnorm = gravity.norm(),
  4122. gx = gravity.x,
  4123. gy = gravity.y,
  4124. gz = gravity.z,
  4125. i=0;
  4126. if(doProfiling){
  4127. profilingStart = now();
  4128. }
  4129. if(dt===undefined){
  4130. dt = this.last_dt || this.default_dt;
  4131. }
  4132. // Add gravity to all objects
  4133. for(i=0; i!==N; i++){
  4134. var bi = bodies[i];
  4135. if(bi.motionstate & DYNAMIC){ // Only for dynamic bodies
  4136. var f = bi.force, m = bi.mass;
  4137. f.x += m*gx;
  4138. f.y += m*gy;
  4139. f.z += m*gz;
  4140. }
  4141. }
  4142. // Update subsystems
  4143. for(var i=0, Nsubsystems=this.subsystems.length; i!==Nsubsystems; i++){
  4144. this.subsystems[i].update();
  4145. }
  4146. // 1. Collision detection
  4147. if(doProfiling){ profilingStart = now(); }
  4148. p1.length = 0; // Clean up pair arrays from last step
  4149. p2.length = 0;
  4150. this.broadphase.collisionPairs(this,p1,p2);
  4151. if(doProfiling){ profile.broadphase = now() - profilingStart; }
  4152. this.collisionMatrixTick();
  4153. // Generate contacts
  4154. if(doProfiling){ profilingStart = now(); }
  4155. var oldcontacts = World_step_oldContacts;
  4156. var NoldContacts = contacts.length;
  4157. for(i=0; i!==NoldContacts; i++){
  4158. oldcontacts.push(contacts[i]);
  4159. }
  4160. contacts.length = 0;
  4161. this.contactgen.getContacts(p1,p2,
  4162. this,
  4163. contacts,
  4164. oldcontacts // To be reused
  4165. );
  4166. if(doProfiling){
  4167. profile.nearphase = now() - profilingStart;
  4168. }
  4169. // Loop over all collisions
  4170. if(doProfiling){
  4171. profilingStart = now();
  4172. }
  4173. var ncontacts = contacts.length;
  4174. // Transfer FrictionEquation from current list to the pool for reuse
  4175. var NoldFrictionEquations = this.frictionEquations.length;
  4176. for(i=0; i!==NoldFrictionEquations; i++){
  4177. frictionEquationPool.push(this.frictionEquations[i]);
  4178. }
  4179. this.frictionEquations.length = 0;
  4180. for(var k=0; k!==ncontacts; k++){
  4181. // Current contact
  4182. var c = contacts[k];
  4183. // Get current collision indeces
  4184. var bi=c.bi, bj=c.bj;
  4185. // Resolve indeces
  4186. var i = bodies.indexOf(bi), j = bodies.indexOf(bj);
  4187. // Get collision properties
  4188. var cm = this.getContactMaterial(bi.material,bj.material) || this.defaultContactMaterial;
  4189. var mu = cm.friction;
  4190. var e = cm.restitution;
  4191. // g = ( xj + rj - xi - ri ) .dot ( ni )
  4192. var gvec = World_step_gvec;
  4193. gvec.set(bj.position.x + c.rj.x - bi.position.x - c.ri.x,
  4194. bj.position.y + c.rj.y - bi.position.y - c.ri.y,
  4195. bj.position.z + c.rj.z - bi.position.z - c.ri.z);
  4196. var g = gvec.dot(c.ni); // Gap, negative if penetration
  4197. // Action if penetration
  4198. if(g<0.0){
  4199. c.restitution = cm.restitution;
  4200. c.penetration = g;
  4201. c.stiffness = cm.contactEquationStiffness;
  4202. c.regularizationTime = cm.contactEquationRegularizationTime;
  4203. solver.addEquation(c);
  4204. // Add friction constraint equation
  4205. if(mu > 0){
  4206. // Create 2 tangent equations
  4207. var mug = mu*gnorm;
  4208. var reducedMass = (bi.invMass + bj.invMass);
  4209. if(reducedMass > 0){
  4210. reducedMass = 1/reducedMass;
  4211. }
  4212. var pool = frictionEquationPool;
  4213. var c1 = pool.length ? pool.pop() : new FrictionEquation(bi,bj,mug*reducedMass);
  4214. var c2 = pool.length ? pool.pop() : new FrictionEquation(bi,bj,mug*reducedMass);
  4215. this.frictionEquations.push(c1);
  4216. this.frictionEquations.push(c2);
  4217. c1.bi = c2.bi = bi;
  4218. c1.bj = c2.bj = bj;
  4219. c1.minForce = c2.minForce = -mug*reducedMass;
  4220. c1.maxForce = c2.maxForce = mug*reducedMass;
  4221. // Copy over the relative vectors
  4222. c.ri.copy(c1.ri);
  4223. c.rj.copy(c1.rj);
  4224. c.ri.copy(c2.ri);
  4225. c.rj.copy(c2.rj);
  4226. // Construct tangents
  4227. c.ni.tangents(c1.t,c2.t);
  4228. // Add equations to solver
  4229. solver.addEquation(c1);
  4230. solver.addEquation(c2);
  4231. }
  4232. // Now we know that i and j are in contact. Set collision matrix state
  4233. this.collisionMatrixSet(i,j,1,true);
  4234. if(this.collisionMatrixGet(i,j,true)!==this.collisionMatrixGet(i,j,false)){
  4235. // First contact!
  4236. // 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.
  4237. World_step_collideEvent.with = bj;
  4238. World_step_collideEvent.contact = c;
  4239. bi.dispatchEvent(World_step_collideEvent);
  4240. World_step_collideEvent.with = bi;
  4241. bj.dispatchEvent(World_step_collideEvent);
  4242. bi.wakeUp();
  4243. bj.wakeUp();
  4244. }
  4245. }
  4246. }
  4247. if(doProfiling){
  4248. profile.makeContactConstraints = now() - profilingStart;
  4249. }
  4250. if(doProfiling){
  4251. profilingStart = now();
  4252. }
  4253. // Add user-added constraints
  4254. var Nconstraints = constraints.length;
  4255. for(i=0; i!==Nconstraints; i++){
  4256. var c = constraints[i];
  4257. c.update();
  4258. for(var j=0, Neq=c.equations.length; j!==Neq; j++){
  4259. var eq = c.equations[j];
  4260. solver.addEquation(eq);
  4261. }
  4262. }
  4263. // Solve the constrained system
  4264. solver.solve(dt,this);
  4265. if(doProfiling){
  4266. profile.solve = now() - profilingStart;
  4267. }
  4268. // Remove all contacts from solver
  4269. solver.removeAllEquations();
  4270. // Apply damping, see http://code.google.com/p/bullet/issues/detail?id=74 for details
  4271. var pow = Math.pow;
  4272. for(i=0; i!==N; i++){
  4273. var bi = bodies[i];
  4274. if(bi.motionstate & DYNAMIC){ // Only for dynamic bodies
  4275. var ld = pow(1.0 - bi.linearDamping,dt);
  4276. var v = bi.velocity;
  4277. v.mult(ld,v);
  4278. var av = bi.angularVelocity;
  4279. if(av){
  4280. var ad = pow(1.0 - bi.angularDamping,dt);
  4281. av.mult(ad,av);
  4282. }
  4283. }
  4284. }
  4285. this.dispatchEvent(World_step_postStepEvent);
  4286. // Invoke pre-step callbacks
  4287. for(i=0; i!==N; i++){
  4288. var bi = bodies[i];
  4289. if(bi.preStep){
  4290. bi.preStep.call(bi);
  4291. }
  4292. }
  4293. // Leap frog
  4294. // vnew = v + h*f/m
  4295. // xnew = x + h*vnew
  4296. if(doProfiling){
  4297. profilingStart = now();
  4298. }
  4299. var q = World_step_step_q;
  4300. var w = World_step_step_w;
  4301. var wq = World_step_step_wq;
  4302. var stepnumber = this.stepnumber;
  4303. var DYNAMIC_OR_KINEMATIC = CANNON.Body.DYNAMIC | CANNON.Body.KINEMATIC;
  4304. var quatNormalize = stepnumber % (this.quatNormalizeSkip+1) === 0;
  4305. var quatNormalizeFast = this.quatNormalizeFast;
  4306. var half_dt = dt * 0.5;
  4307. var PLANE = CANNON.Shape.types.PLANE,
  4308. CONVEX = CANNON.Shape.types.CONVEXPOLYHEDRON;
  4309. for(i=0; i!==N; i++){
  4310. var b = bodies[i],
  4311. s = b.shape,
  4312. force = b.force,
  4313. tau = b.tau;
  4314. if((b.motionstate & DYNAMIC_OR_KINEMATIC)){ // Only for dynamic
  4315. var velo = b.velocity,
  4316. angularVelo = b.angularVelocity,
  4317. pos = b.position,
  4318. quat = b.quaternion,
  4319. invMass = b.invMass,
  4320. invInertia = b.invInertia;
  4321. velo.x += force.x * invMass * dt;
  4322. velo.y += force.y * invMass * dt;
  4323. velo.z += force.z * invMass * dt;
  4324. if(b.angularVelocity){
  4325. angularVelo.x += tau.x * invInertia.x * dt;
  4326. angularVelo.y += tau.y * invInertia.y * dt;
  4327. angularVelo.z += tau.z * invInertia.z * dt;
  4328. }
  4329. // Use new velocity - leap frog
  4330. if(!b.isSleeping()){
  4331. pos.x += velo.x * dt;
  4332. pos.y += velo.y * dt;
  4333. pos.z += velo.z * dt;
  4334. if(b.angularVelocity){
  4335. w.set(angularVelo.x, angularVelo.y, angularVelo.z, 0);
  4336. w.mult(quat,wq);
  4337. quat.x += half_dt * wq.x;
  4338. quat.y += half_dt * wq.y;
  4339. quat.z += half_dt * wq.z;
  4340. quat.w += half_dt * wq.w;
  4341. if(quatNormalize){
  4342. if(quatNormalizeFast){
  4343. quat.normalizeFast();
  4344. } else {
  4345. quat.normalize();
  4346. }
  4347. }
  4348. }
  4349. if(b.aabbmin){
  4350. b.aabbNeedsUpdate = true;
  4351. }
  4352. }
  4353. if(s){
  4354. switch(s.type){
  4355. case PLANE:
  4356. s.worldNormalNeedsUpdate = true;
  4357. break;
  4358. case CONVEX:
  4359. s.worldFaceNormalsNeedsUpdate = true;
  4360. s.worldVerticesNeedsUpdate = true;
  4361. break;
  4362. }
  4363. }
  4364. }
  4365. b.force.set(0,0,0);
  4366. if(b.tau){
  4367. b.tau.set(0,0,0);
  4368. }
  4369. }
  4370. if(doProfiling){
  4371. profile.integrate = now() - profilingStart;
  4372. }
  4373. // Update world time
  4374. this.time += dt;
  4375. this.stepnumber += 1;
  4376. this.dispatchEvent(World_step_postStepEvent);
  4377. // Invoke post-step callbacks
  4378. for(i=0; i!==N; i++){
  4379. var bi = bodies[i];
  4380. var postStep = bi.postStep;
  4381. if(postStep){
  4382. postStep.call(bi);
  4383. }
  4384. }
  4385. // Update world inertias
  4386. // @todo should swap autoUpdate mechanism for .xxxNeedsUpdate
  4387. for(i=0; i!==N; i++){
  4388. var b = bodies[i];
  4389. if(b.inertiaWorldAutoUpdate){
  4390. b.quaternion.vmult(b.inertia,b.inertiaWorld);
  4391. }
  4392. if(b.invInertiaWorldAutoUpdate){
  4393. b.quaternion.vmult(b.invInertia,b.invInertiaWorld);
  4394. }
  4395. }
  4396. // Sleeping update
  4397. if(this.allowSleep){
  4398. for(i=0; i!==N; i++){
  4399. bodies[i].sleepTick(this.time);
  4400. }
  4401. }
  4402. };
  4403. /**
  4404. * @class CANNON.ContactGenerator
  4405. * @brief Helper class for the World. Generates ContactEquations.
  4406. * @todo Sphere-ConvexPolyhedron contacts
  4407. * @todo Contact reduction
  4408. */
  4409. CANNON.ContactGenerator = function(){
  4410. /**
  4411. * @property bool contactReduction
  4412. * @memberof CANNON.ContactGenerator
  4413. * @brief Turns on or off contact reduction. Can be handy to turn off when debugging new collision types.
  4414. */
  4415. this.contactReduction = false;
  4416. // Contact point objects that can be reused
  4417. var contactPointPool = [];
  4418. var v3pool = new CANNON.Vec3Pool();
  4419. /*
  4420. * Make a contact object.
  4421. * @return object
  4422. * @todo reuse old contact point objects
  4423. */
  4424. function makeResult(bi,bj){
  4425. if(contactPointPool.length){
  4426. var c = contactPointPool.pop();
  4427. c.bi = bi;
  4428. c.bj = bj;
  4429. return c;
  4430. } else {
  4431. return new CANNON.ContactEquation(bi,bj);
  4432. }
  4433. }
  4434. /*
  4435. * Swaps the body references in the contact
  4436. * @param object r
  4437. */
  4438. function swapResult(r){
  4439. var temp;
  4440. temp = r.ri;
  4441. r.ri = r.rj;
  4442. r.rj = temp;
  4443. r.ni.negate(r.ni);
  4444. temp = r.bi;
  4445. r.bi = r.bj;
  4446. r.bj = temp;
  4447. }
  4448. function sphereSphere(result,si,sj,xi,xj,qi,qj,bi,bj){
  4449. // We will have only one contact in this case
  4450. var r = makeResult(bi,bj);
  4451. // Contact normal
  4452. bj.position.vsub(xi, r.ni);
  4453. r.ni.normalize();
  4454. // Contact point locations
  4455. r.ni.copy(r.ri);
  4456. r.ni.copy(r.rj);
  4457. r.ri.mult(si.radius, r.ri);
  4458. r.rj.mult(-sj.radius, r.rj);
  4459. result.push(r);
  4460. }
  4461. var point_on_plane_to_sphere = new CANNON.Vec3();
  4462. var plane_to_sphere_ortho = new CANNON.Vec3();
  4463. function spherePlane(result,si,sj,xi,xj,qi,qj,bi,bj){
  4464. // We will have one contact in this case
  4465. var r = makeResult(bi,bj);
  4466. // Contact normal
  4467. r.ni.set(0,0,1);
  4468. qj.vmult(r.ni,r.ni);
  4469. r.ni.negate(r.ni); // body i is the sphere, flip normal
  4470. r.ni.normalize();
  4471. // Vector from sphere center to contact point
  4472. r.ni.mult(si.radius,r.ri);
  4473. // Project down sphere on plane
  4474. xi.vsub(xj,point_on_plane_to_sphere);
  4475. r.ni.mult(r.ni.dot(point_on_plane_to_sphere),plane_to_sphere_ortho);
  4476. point_on_plane_to_sphere.vsub(plane_to_sphere_ortho,r.rj); // The sphere position projected to plane
  4477. if(plane_to_sphere_ortho.norm2() <= si.radius*si.radius){
  4478. result.push(r);
  4479. }
  4480. }
  4481. // See http://bulletphysics.com/Bullet/BulletFull/SphereTriangleDetector_8cpp_source.html
  4482. var pointInPolygon_edge = new CANNON.Vec3();
  4483. var pointInPolygon_edge_x_normal = new CANNON.Vec3();
  4484. var pointInPolygon_vtp = new CANNON.Vec3();
  4485. function pointInPolygon(verts, normal, p){
  4486. var positiveResult = null;
  4487. var N = verts.length;
  4488. for(var i=0; i!==N; i++){
  4489. var v = verts[i];
  4490. // Get edge to the next vertex
  4491. var edge = pointInPolygon_edge;
  4492. verts[(i+1) % (N)].vsub(v,edge);
  4493. // Get cross product between polygon normal and the edge
  4494. var edge_x_normal = pointInPolygon_edge_x_normal;
  4495. //var edge_x_normal = new CANNON.Vec3();
  4496. edge.cross(normal,edge_x_normal);
  4497. // Get vector between point and current vertex
  4498. var vertex_to_p = pointInPolygon_vtp;
  4499. p.vsub(v,vertex_to_p);
  4500. // This dot product determines which side of the edge the point is
  4501. var r = edge_x_normal.dot(vertex_to_p);
  4502. // If all such dot products have same sign, we are inside the polygon.
  4503. if(positiveResult===null || (r>0 && positiveResult===true) || (r<=0 && positiveResult===false)){
  4504. if(positiveResult===null){
  4505. positiveResult = r>0;
  4506. }
  4507. continue;
  4508. } else {
  4509. return false; // Encountered some other sign. Exit.
  4510. }
  4511. }
  4512. // If we got here, all dot products were of the same sign.
  4513. return true;
  4514. }
  4515. var box_to_sphere = new CANNON.Vec3();
  4516. var sphereBox_ns = new CANNON.Vec3();
  4517. var sphereBox_ns1 = new CANNON.Vec3();
  4518. var sphereBox_ns2 = new CANNON.Vec3();
  4519. var sphereBox_sides = [new CANNON.Vec3(),new CANNON.Vec3(),new CANNON.Vec3(),new CANNON.Vec3(),new CANNON.Vec3(),new CANNON.Vec3()];
  4520. var sphereBox_sphere_to_corner = new CANNON.Vec3();
  4521. var sphereBox_side_ns = new CANNON.Vec3();
  4522. var sphereBox_side_ns1 = new CANNON.Vec3();
  4523. var sphereBox_side_ns2 = new CANNON.Vec3();
  4524. function sphereBox(result,si,sj,xi,xj,qi,qj,bi,bj){
  4525. // we refer to the box as body j
  4526. var sides = sphereBox_sides;
  4527. xi.vsub(xj,box_to_sphere);
  4528. sj.getSideNormals(sides,qj);
  4529. var R = si.radius;
  4530. var penetrating_sides = [];
  4531. // Check side (plane) intersections
  4532. var found = false;
  4533. // Store the resulting side penetration info
  4534. var side_ns = sphereBox_side_ns;
  4535. var side_ns1 = sphereBox_side_ns1;
  4536. var side_ns2 = sphereBox_side_ns2;
  4537. var side_h = null;
  4538. var side_penetrations = 0;
  4539. var side_dot1 = 0;
  4540. var side_dot2 = 0;
  4541. var side_distance = null;
  4542. for(var idx=0,nsides=sides.length; idx!==nsides && found===false; idx++){
  4543. // Get the plane side normal (ns)
  4544. var ns = sphereBox_ns;
  4545. sides[idx].copy(ns);
  4546. var h = ns.norm();
  4547. ns.normalize();
  4548. // The normal/distance dot product tells which side of the plane we are
  4549. var dot = box_to_sphere.dot(ns);
  4550. if(dot<h+R && dot>0){
  4551. // Intersects plane. Now check the other two dimensions
  4552. var ns1 = sphereBox_ns1;
  4553. var ns2 = sphereBox_ns2;
  4554. sides[(idx+1)%3].copy(ns1);
  4555. sides[(idx+2)%3].copy(ns2);
  4556. var h1 = ns1.norm();
  4557. var h2 = ns2.norm();
  4558. ns1.normalize();
  4559. ns2.normalize();
  4560. var dot1 = box_to_sphere.dot(ns1);
  4561. var dot2 = box_to_sphere.dot(ns2);
  4562. if(dot1<h1 && dot1>-h1 && dot2<h2 && dot2>-h2){
  4563. var dist = Math.abs(dot-h-R);
  4564. if(side_distance===null || dist < side_distance){
  4565. side_distance = dist;
  4566. side_dot1 = dot1;
  4567. side_dot2 = dot2;
  4568. side_h = h;
  4569. ns.copy(side_ns);
  4570. ns1.copy(side_ns1);
  4571. ns2.copy(side_ns2);
  4572. side_penetrations++;
  4573. }
  4574. }
  4575. }
  4576. }
  4577. if(side_penetrations){
  4578. found = true;
  4579. var r = makeResult(bi,bj);
  4580. side_ns.mult(-R,r.ri); // Sphere r
  4581. side_ns.copy(r.ni);
  4582. r.ni.negate(r.ni); // Normal should be out of sphere
  4583. side_ns.mult(side_h,side_ns);
  4584. side_ns1.mult(side_dot1,side_ns1);
  4585. side_ns.vadd(side_ns1,side_ns);
  4586. side_ns2.mult(side_dot2,side_ns2);
  4587. side_ns.vadd(side_ns2,r.rj);
  4588. result.push(r);
  4589. }
  4590. // Check corners
  4591. var rj = v3pool.get();
  4592. var sphere_to_corner = sphereBox_sphere_to_corner;
  4593. for(var j=0; j!==2 && !found; j++){
  4594. for(var k=0; k!==2 && !found; k++){
  4595. for(var l=0; l!==2 && !found; l++){
  4596. rj.set(0,0,0);
  4597. if(j){
  4598. rj.vadd(sides[0],rj);
  4599. } else {
  4600. rj.vsub(sides[0],rj);
  4601. }
  4602. if(k){
  4603. rj.vadd(sides[1],rj);
  4604. } else {
  4605. rj.vsub(sides[1],rj);
  4606. }
  4607. if(l){
  4608. rj.vadd(sides[2],rj);
  4609. } else {
  4610. rj.vsub(sides[2],rj);
  4611. }
  4612. // World position of corner
  4613. xj.vadd(rj,sphere_to_corner);
  4614. sphere_to_corner.vsub(xi,sphere_to_corner);
  4615. if(sphere_to_corner.norm2() < R*R){
  4616. found = true;
  4617. var r = makeResult(bi,bj);
  4618. sphere_to_corner.copy(r.ri);
  4619. r.ri.normalize();
  4620. r.ri.copy(r.ni);
  4621. r.ri.mult(R,r.ri);
  4622. rj.copy(r.rj);
  4623. result.push(r);
  4624. }
  4625. }
  4626. }
  4627. }
  4628. v3pool.release(rj);
  4629. rj = null;
  4630. // Check edges
  4631. var edgeTangent = v3pool.get();
  4632. var edgeCenter = v3pool.get();
  4633. var r = v3pool.get(); // r = edge center to sphere center
  4634. var orthogonal = v3pool.get();
  4635. var dist = v3pool.get();
  4636. var Nsides = sides.length;
  4637. for(var j=0; j!==Nsides && !found; j++){
  4638. for(var k=0; k!==Nsides && !found; k++){
  4639. if(j%3 !== k%3){
  4640. // Get edge tangent
  4641. sides[k].cross(sides[j],edgeTangent);
  4642. edgeTangent.normalize();
  4643. sides[j].vadd(sides[k], edgeCenter);
  4644. xi.copy(r);
  4645. r.vsub(edgeCenter,r);
  4646. r.vsub(xj,r);
  4647. var orthonorm = r.dot(edgeTangent); // distance from edge center to sphere center in the tangent direction
  4648. edgeTangent.mult(orthonorm,orthogonal); // Vector from edge center to sphere center in the tangent direction
  4649. // Find the third side orthogonal to this one
  4650. var l = 0;
  4651. while(l===j%3 || l===k%3){
  4652. l++;
  4653. }
  4654. // vec from edge center to sphere projected to the plane orthogonal to the edge tangent
  4655. xi.copy(dist);
  4656. dist.vsub(orthogonal,dist);
  4657. dist.vsub(edgeCenter,dist);
  4658. dist.vsub(xj,dist);
  4659. // Distances in tangent direction and distance in the plane orthogonal to it
  4660. var tdist = Math.abs(orthonorm);
  4661. var ndist = dist.norm();
  4662. if(tdist < sides[l].norm() && ndist<R){
  4663. found = true;
  4664. var res = makeResult(bi,bj);
  4665. edgeCenter.vadd(orthogonal,res.rj); // box rj
  4666. res.rj.copy(res.rj);
  4667. dist.negate(res.ni);
  4668. res.ni.normalize();
  4669. res.rj.copy(res.ri);
  4670. res.ri.vadd(xj,res.ri);
  4671. res.ri.vsub(xi,res.ri);
  4672. res.ri.normalize();
  4673. res.ri.mult(R,res.ri);
  4674. result.push(res);
  4675. }
  4676. }
  4677. }
  4678. }
  4679. v3pool.release(edgeTangent,edgeCenter,r,orthogonal,dist);
  4680. }
  4681. var convex_to_sphere = new CANNON.Vec3();
  4682. var sphereConvex_edge = new CANNON.Vec3();
  4683. var sphereConvex_edgeUnit = new CANNON.Vec3();
  4684. var sphereConvex_sphereToCorner = new CANNON.Vec3();
  4685. var sphereConvex_worldCorner = new CANNON.Vec3();
  4686. var sphereConvex_worldNormal = new CANNON.Vec3();
  4687. var sphereConvex_worldPoint = new CANNON.Vec3();
  4688. var sphereConvex_worldSpherePointClosestToPlane = new CANNON.Vec3();
  4689. var sphereConvex_penetrationVec = new CANNON.Vec3();
  4690. var sphereConvex_sphereToWorldPoint = new CANNON.Vec3();
  4691. function sphereConvex(result,si,sj,xi,xj,qi,qj,bi,bj){
  4692. xi.vsub(xj,convex_to_sphere);
  4693. var normals = sj.faceNormals;
  4694. var faces = sj.faces;
  4695. var verts = sj.vertices;
  4696. var R = si.radius;
  4697. var penetrating_sides = [];
  4698. // Check corners
  4699. for(var i=0; i!==verts.length; i++){
  4700. var v = verts[i];
  4701. // World position of corner
  4702. var worldCorner = sphereConvex_worldCorner;
  4703. qj.vmult(v,worldCorner);
  4704. xj.vadd(worldCorner,worldCorner);
  4705. var sphere_to_corner = sphereConvex_sphereToCorner;
  4706. worldCorner.vsub(xi, sphere_to_corner);
  4707. if(sphere_to_corner.norm2()<R*R){
  4708. found = true;
  4709. var r = makeResult(bi,bj);
  4710. sphere_to_corner.copy(r.ri);
  4711. r.ri.normalize();
  4712. r.ri.copy(r.ni);
  4713. r.ri.mult(R,r.ri);
  4714. worldCorner.vsub(xj,r.rj);
  4715. result.push(r);
  4716. return;
  4717. }
  4718. }
  4719. // Check side (plane) intersections
  4720. var found = false;
  4721. for(var i=0,nfaces=faces.length; i!==nfaces && found===false; i++){
  4722. var normal = normals[i];
  4723. var face = faces[i];
  4724. var worldNormal = sphereConvex_worldNormal;
  4725. qj.vmult(normal,worldNormal);
  4726. var worldPoint = sphereConvex_worldPoint;
  4727. qj.vmult(verts[face[0]],worldPoint);
  4728. worldPoint.vadd(xj,worldPoint); // Arbitrary point in the face
  4729. var worldSpherePointClosestToPlane = sphereConvex_worldSpherePointClosestToPlane;
  4730. worldNormal.mult(-R,worldSpherePointClosestToPlane);
  4731. xi.vadd(worldSpherePointClosestToPlane,worldSpherePointClosestToPlane);
  4732. var penetrationVec = sphereConvex_penetrationVec;
  4733. worldSpherePointClosestToPlane.vsub(worldPoint,penetrationVec);
  4734. var penetration = penetrationVec.dot(worldNormal);
  4735. var sphereToWorldPoint = sphereConvex_sphereToWorldPoint;
  4736. xi.vsub(worldPoint,sphereToWorldPoint);
  4737. if(penetration<0 && sphereToWorldPoint.dot(worldNormal)>0){
  4738. // Intersects plane. Now check if the sphere is inside the face polygon
  4739. var faceVerts = []; // Face vertices, in world coords
  4740. for(var j=0, Nverts=face.length; j!==Nverts; j++){
  4741. var worldVertex = v3pool.get();
  4742. qj.vmult(verts[face[j]], worldVertex);
  4743. xj.vadd(worldVertex,worldVertex);
  4744. faceVerts.push(worldVertex);
  4745. }
  4746. if(pointInPolygon(faceVerts,worldNormal,xi)){ // Is the sphere center in the face polygon?
  4747. found = true;
  4748. var r = makeResult(bi,bj);
  4749. worldNormal.mult(-R,r.ri); // Sphere r
  4750. worldNormal.negate(r.ni); // Normal should be out of sphere
  4751. var penetrationVec2 = v3pool.get();
  4752. worldNormal.mult(-penetration,penetrationVec2);
  4753. var penetrationSpherePoint = v3pool.get();
  4754. worldNormal.mult(-R,penetrationSpherePoint);
  4755. //xi.vsub(xj).vadd(penetrationSpherePoint).vadd(penetrationVec2 , r.rj);
  4756. xi.vsub(xj,r.rj);
  4757. r.rj.vadd(penetrationSpherePoint,r.rj);
  4758. r.rj.vadd(penetrationVec2 , r.rj);
  4759. v3pool.release(penetrationVec2);
  4760. v3pool.release(penetrationSpherePoint);
  4761. result.push(r);
  4762. // Release world vertices
  4763. for(var j=0, Nfaceverts=faceVerts.length; j!==Nfaceverts; j++){
  4764. v3pool.release(faceVerts[j]);
  4765. }
  4766. return; // We only expect *one* face contact
  4767. } else {
  4768. // Edge?
  4769. for(var j=0; j!==face.length; j++){
  4770. // Get two world transformed vertices
  4771. var v1 = v3pool.get();
  4772. var v2 = v3pool.get();
  4773. qj.vmult(verts[face[(j+1)%face.length]], v1);
  4774. qj.vmult(verts[face[(j+2)%face.length]], v2);
  4775. xj.vadd(v1, v1);
  4776. xj.vadd(v2, v2);
  4777. // Construct edge vector
  4778. var edge = sphereConvex_edge;
  4779. v2.vsub(v1,edge);
  4780. // Construct the same vector, but normalized
  4781. var edgeUnit = sphereConvex_edgeUnit;
  4782. edge.unit(edgeUnit);
  4783. // p is xi projected onto the edge
  4784. var p = v3pool.get();
  4785. var v1_to_xi = v3pool.get();
  4786. xi.vsub(v1, v1_to_xi);
  4787. var dot = v1_to_xi.dot(edgeUnit);
  4788. edgeUnit.mult(dot, p);
  4789. p.vadd(v1, p);
  4790. // Compute a vector from p to the center of the sphere
  4791. var xi_to_p = v3pool.get();
  4792. p.vsub(xi, xi_to_p);
  4793. // Collision if the edge-sphere distance is less than the radius
  4794. // AND if p is in between v1 and v2
  4795. if(dot > 0 && dot*dot<edge.norm2() && xi_to_p.norm2() < R*R){ // Collision if the edge-sphere distance is less than the radius
  4796. // Edge contact!
  4797. var r = makeResult(bi,bj);
  4798. p.vsub(xj,r.rj);
  4799. p.vsub(xi,r.ni);
  4800. r.ni.normalize();
  4801. r.ni.mult(R,r.ri);
  4802. result.push(r);
  4803. // Release world vertices
  4804. for(var j=0, Nfaceverts=faceVerts.length; j!==Nfaceverts; j++){
  4805. v3pool.release(faceVerts[j]);
  4806. }
  4807. v3pool.release(v1);
  4808. v3pool.release(v2);
  4809. v3pool.release(p);
  4810. v3pool.release(xi_to_p);
  4811. v3pool.release(v1_to_xi);
  4812. return;
  4813. }
  4814. v3pool.release(v1);
  4815. v3pool.release(v2);
  4816. v3pool.release(p);
  4817. v3pool.release(xi_to_p);
  4818. v3pool.release(v1_to_xi);
  4819. }
  4820. }
  4821. // Release world vertices
  4822. for(var j=0, Nfaceverts=faceVerts.length; j!==Nfaceverts; j++){
  4823. v3pool.release(faceVerts[j]);
  4824. }
  4825. }
  4826. }
  4827. }
  4828. var planeBox_normal = new CANNON.Vec3();
  4829. var plane_to_corner = new CANNON.Vec3();
  4830. function planeBox(result,si,sj,xi,xj,qi,qj,bi,bj){
  4831. planeConvex(result,si,sj.convexPolyhedronRepresentation,xi,xj,qi,qj,bi,bj);
  4832. }
  4833. /*
  4834. * Go recursive for compound shapes
  4835. * @param Shape si
  4836. * @param CompoundShape sj
  4837. */
  4838. var recurseCompound_v3pool = [];
  4839. var recurseCompound_quatpool = [];
  4840. function recurseCompound(result,si,sj,xi,xj,qi,qj,bi,bj){
  4841. var v3pool = recurseCompound_v3pool;
  4842. var quatPool = recurseCompound_quatpool;
  4843. var nr = 0;
  4844. for(var i=0, Nchildren=sj.childShapes.length; i!==Nchildren; i++){
  4845. var r = [];
  4846. var newQuat = quatPool.pop() || new CANNON.Quaternion();
  4847. var newPos = v3pool.pop() || new CANNON.Vec3();
  4848. qj.mult(sj.childOrientations[i],newQuat); // Can't reuse these since nearPhase() may recurse
  4849. newQuat.normalize();
  4850. //var newPos = xj.vadd(qj.vmult(sj.childOffsets[i]));
  4851. qj.vmult(sj.childOffsets[i],newPos);
  4852. xj.vadd(newPos,newPos);
  4853. nearPhase(r,
  4854. si,
  4855. sj.childShapes[i],
  4856. xi,
  4857. newPos,//xj.vadd(qj.vmult(sj.childOffsets[i])), // Transform the shape to its local frame
  4858. qi,
  4859. newQuat, // Accumulate orientation
  4860. bi,
  4861. bj);
  4862. // Release vector and quat
  4863. quatPool.push(newQuat);
  4864. var tempVec = newPos;
  4865. if(!si){
  4866. nr+= r.length;
  4867. }
  4868. for(var j=0; j!==r.length; j++){
  4869. // The "rj" vector is in world coords, though we must add the world child offset vector.
  4870. //r[j].rj.vadd(qj.vmult(sj.childOffsets[i]),r[j].rj);
  4871. qj.vmult(sj.childOffsets[i],tempVec);
  4872. r[j].rj.vadd(tempVec,r[j].rj);
  4873. result.push(r[j]);
  4874. }
  4875. v3pool.push(newPos);
  4876. }
  4877. }
  4878. var planeConvex_v = new CANNON.Vec3();
  4879. var planeConvex_normal = new CANNON.Vec3();
  4880. var planeConvex_relpos = new CANNON.Vec3();
  4881. var planeConvex_projected = new CANNON.Vec3();
  4882. function planeConvex(result,si,sj,xi,xj,qi,qj,bi,bj){
  4883. // Simply return the points behind the plane.
  4884. var v = planeConvex_v;
  4885. var normal = planeConvex_normal;
  4886. normal.set(0,0,1);
  4887. qi.vmult(normal,normal); // Turn normal according to plane orientation
  4888. var relpos = planeConvex_relpos;
  4889. for(var i=0; i!==sj.vertices.length; i++){
  4890. sj.vertices[i].copy(v);
  4891. // Transform to world coords
  4892. qj.vmult(v,v);
  4893. xj.vadd(v,v);
  4894. v.vsub(xi,relpos);
  4895. var dot = normal.dot(relpos);
  4896. if(dot<=0.0){
  4897. // Get vertex position projected on plane
  4898. var projected = planeConvex_projected;
  4899. normal.mult(normal.dot(v),projected);
  4900. v.vsub(projected,projected);
  4901. var r = makeResult(bi,bj);
  4902. normal.copy( r.ni ); // Contact normal is the plane normal out from plane
  4903. projected.copy(r.ri); // From plane to vertex projected on plane
  4904. // rj is now just the vertex position
  4905. v.vsub(xj,r.rj);
  4906. result.push(r);
  4907. }
  4908. }
  4909. }
  4910. var convexConvex_sepAxis = new CANNON.Vec3();
  4911. var convexConvex_q = new CANNON.Vec3();
  4912. function convexConvex(result,si,sj,xi,xj,qi,qj,bi,bj){
  4913. var sepAxis = convexConvex_sepAxis;
  4914. if(si.findSeparatingAxis(sj,xi,qi,xj,qj,sepAxis)){
  4915. var res = [];
  4916. var q = convexConvex_q;
  4917. si.clipAgainstHull(xi,qi,sj,xj,qj,sepAxis,-100,100,res);
  4918. //console.log(res.length);
  4919. for(var j=0; j!==res.length; j++){
  4920. var r = makeResult(bi,bj);
  4921. sepAxis.negate(r.ni);
  4922. res[j].normal.negate(q);
  4923. q.mult(res[j].depth,q);
  4924. res[j].point.vadd(q,r.ri);
  4925. res[j].point.copy(r.rj);
  4926. // Contact points are in world coordinates. Transform back to relative
  4927. r.rj.vsub(xj,r.rj);
  4928. r.ri.vsub(xi,r.ri);
  4929. result.push(r);
  4930. }
  4931. }
  4932. }
  4933. var particlePlane_normal = new CANNON.Vec3();
  4934. var particlePlane_relpos = new CANNON.Vec3();
  4935. var particlePlane_projected = new CANNON.Vec3();
  4936. function particlePlane(result,si,sj,xi,xj,qi,qj,bi,bj){
  4937. var normal = particlePlane_normal;
  4938. normal.set(0,0,1);
  4939. bj.quaternion.vmult(normal,normal); // Turn normal according to plane orientation
  4940. var relpos = particlePlane_relpos;
  4941. xi.vsub(bj.position,relpos);
  4942. var dot = normal.dot(relpos);
  4943. if(dot<=0.0){
  4944. var r = makeResult(bi,bj);
  4945. normal.copy( r.ni ); // Contact normal is the plane normal
  4946. r.ni.negate(r.ni);
  4947. r.ri.set(0,0,0); // Center of particle
  4948. // Get particle position projected on plane
  4949. var projected = particlePlane_projected;
  4950. normal.mult(normal.dot(xi),projected);
  4951. xi.vsub(projected,projected);
  4952. //projected.vadd(bj.position,projected);
  4953. // rj is now the projected world position minus plane position
  4954. projected.copy(r.rj);
  4955. result.push(r);
  4956. }
  4957. }
  4958. var particleSphere_normal = new CANNON.Vec3();
  4959. function particleSphere(result,si,sj,xi,xj,qi,qj,bi,bj){
  4960. // The normal is the unit vector from sphere center to particle center
  4961. var normal = particleSphere_normal;
  4962. normal.set(0,0,1);
  4963. xi.vsub(xj,normal);
  4964. var lengthSquared = normal.norm2();
  4965. if(lengthSquared <= sj.radius * sj.radius){
  4966. var r = makeResult(bi,bj);
  4967. normal.normalize();
  4968. normal.copy(r.rj);
  4969. r.rj.mult(sj.radius,r.rj);
  4970. normal.copy( r.ni ); // Contact normal
  4971. r.ni.negate(r.ni);
  4972. r.ri.set(0,0,0); // Center of particle
  4973. result.push(r);
  4974. }
  4975. }
  4976. // WIP
  4977. var cqj = new CANNON.Quaternion();
  4978. var particleConvex_local = new CANNON.Vec3();
  4979. var particleConvex_normal = new CANNON.Vec3();
  4980. var particleConvex_penetratedFaceNormal = new CANNON.Vec3();
  4981. var particleConvex_vertexToParticle = new CANNON.Vec3();
  4982. var particleConvex_worldPenetrationVec = new CANNON.Vec3();
  4983. function particleConvex(result,si,sj,xi,xj,qi,qj,bi,bj){
  4984. var penetratedFaceIndex = -1;
  4985. var penetratedFaceNormal = particleConvex_penetratedFaceNormal;
  4986. var worldPenetrationVec = particleConvex_worldPenetrationVec;
  4987. var minPenetration = null;
  4988. var numDetectedFaces = 0;
  4989. // Convert particle position xi to local coords in the convex
  4990. var local = particleConvex_local;
  4991. xi.copy(local);
  4992. local.vsub(xj,local); // Convert position to relative the convex origin
  4993. qj.conjugate(cqj);
  4994. cqj.vmult(local,local);
  4995. if(sj.pointIsInside(local)){
  4996. if(sj.worldVerticesNeedsUpdate){
  4997. sj.computeWorldVertices(xj,qj);
  4998. }
  4999. if(sj.worldFaceNormalsNeedsUpdate){
  5000. sj.computeWorldFaceNormals(qj);
  5001. }
  5002. // For each world polygon in the polyhedra
  5003. for(var i=0,nfaces=sj.faces.length; i!==nfaces; i++){
  5004. // Construct world face vertices
  5005. var verts = [ sj.worldVertices[ sj.faces[i][0] ] ];
  5006. var normal = sj.worldFaceNormals[i];
  5007. // Check how much the particle penetrates the polygon plane.
  5008. xi.vsub(verts[0],particleConvex_vertexToParticle);
  5009. var penetration = -normal.dot(particleConvex_vertexToParticle);
  5010. if(minPenetration===null || Math.abs(penetration)<Math.abs(minPenetration)){
  5011. minPenetration = penetration;
  5012. penetratedFaceIndex = i;
  5013. normal.copy(penetratedFaceNormal);
  5014. numDetectedFaces++;
  5015. }
  5016. }
  5017. if(penetratedFaceIndex!==-1){
  5018. // Setup contact
  5019. var r = makeResult(bi,bj);
  5020. penetratedFaceNormal.mult(minPenetration, worldPenetrationVec);
  5021. // rj is the particle position projected to the face
  5022. worldPenetrationVec.vadd(xi,worldPenetrationVec);
  5023. worldPenetrationVec.vsub(xj,worldPenetrationVec);
  5024. worldPenetrationVec.copy(r.rj);
  5025. //var projectedToFace = xi.vsub(xj).vadd(worldPenetrationVec);
  5026. //projectedToFace.copy(r.rj);
  5027. //qj.vmult(r.rj,r.rj);
  5028. penetratedFaceNormal.negate( r.ni ); // Contact normal
  5029. r.ri.set(0,0,0); // Center of particle
  5030. result.push(r);
  5031. } else {
  5032. console.warn("Point found inside convex, but did not find penetrating face!");
  5033. }
  5034. }
  5035. }
  5036. /*
  5037. * Near phase calculation, get the contact point, normal, etc.
  5038. * @param array result The result one will get back with all the contact point information
  5039. * @param Shape si Colliding shape. If not given, particle is assumed.
  5040. * @param Shape sj
  5041. * @param Vec3 xi Position of the center of mass
  5042. * @param Vec3 xj
  5043. * @param Quaternion qi Rotation around the center of mass
  5044. * @param Quaternion qj
  5045. * @todo All collision cases
  5046. */
  5047. function nearPhase(result,si,sj,xi,xj,qi,qj,bi,bj){
  5048. var swapped = false,
  5049. types = CANNON.Shape.types,
  5050. SPHERE = types.SPHERE,
  5051. PLANE = types.PLANE,
  5052. BOX = types.BOX,
  5053. COMPOUND = types.COMPOUND,
  5054. CONVEXPOLYHEDRON = types.CONVEXPOLYHEDRON;
  5055. if(si && sj){
  5056. if(si.type > sj.type){
  5057. var temp;
  5058. temp=sj;
  5059. sj=si;
  5060. si=temp;
  5061. temp=xj;
  5062. xj=xi;
  5063. xi=temp;
  5064. temp=qj;
  5065. qj=qi;
  5066. qi=temp;
  5067. temp=bj;
  5068. bj=bi;
  5069. bi=temp;
  5070. swapped = true;
  5071. }
  5072. } else {
  5073. // Particle!
  5074. if(si && !sj){
  5075. var temp;
  5076. temp=sj;
  5077. sj=si;
  5078. si=temp;
  5079. temp=xj;
  5080. xj=xi;
  5081. xi=temp;
  5082. temp=qj;
  5083. qj=qi;
  5084. qi=temp;
  5085. temp=bj;
  5086. bj=bi;
  5087. bi=temp;
  5088. swapped = true;
  5089. }
  5090. }
  5091. if(si && sj){
  5092. if(si.type === SPHERE){
  5093. switch(sj.type){
  5094. case SPHERE: // sphere-sphere
  5095. sphereSphere(result,si,sj,xi,xj,qi,qj,bi,bj);
  5096. break;
  5097. case PLANE: // sphere-plane
  5098. spherePlane(result,si,sj,xi,xj,qi,qj,bi,bj);
  5099. break;
  5100. case BOX: // sphere-box
  5101. sphereBox(result,si,sj,xi,xj,qi,qj,bi,bj);
  5102. break;
  5103. case COMPOUND: // sphere-compound
  5104. recurseCompound(result,si,sj,xi,xj,qi,qj,bi,bj);
  5105. break;
  5106. case CONVEXPOLYHEDRON: // sphere-convexpolyhedron
  5107. sphereConvex(result,si,sj,xi,xj,qi,qj,bi,bj);
  5108. break;
  5109. default:
  5110. console.warn("Collision between CANNON.Shape.types.SPHERE and "+sj.type+" not implemented yet.");
  5111. break;
  5112. }
  5113. } else if(si.type === types.PLANE){
  5114. switch(sj.type){
  5115. case types.PLANE: // plane-plane
  5116. throw new Error("Plane-plane collision... wait, you did WHAT?");
  5117. case types.BOX: // plane-box
  5118. planeBox(result,si,sj,xi,xj,qi,qj,bi,bj);
  5119. break;
  5120. case types.COMPOUND: // plane-compound
  5121. recurseCompound(result,si,sj,xi,xj,qi,qj,bi,bj);
  5122. break;
  5123. case types.CONVEXPOLYHEDRON: // plane-convex polyhedron
  5124. planeConvex(result,si,sj,xi,xj,qi,qj,bi,bj);
  5125. break;
  5126. default:
  5127. console.warn("Collision between CANNON.Shape.types.PLANE and "+sj.type+" not implemented yet.");
  5128. break;
  5129. }
  5130. } else if(si.type===types.BOX){
  5131. switch(sj.type){
  5132. case types.BOX: // box-box
  5133. // Do convex/convex instead
  5134. nearPhase(result,si.convexPolyhedronRepresentation,sj.convexPolyhedronRepresentation,xi,xj,qi,qj,bi,bj);
  5135. break;
  5136. case types.COMPOUND: // box-compound
  5137. recurseCompound(result,si,sj,xi,xj,qi,qj,bi,bj);
  5138. break;
  5139. case types.CONVEXPOLYHEDRON: // box-convexpolyhedron
  5140. // Do convex/convex instead
  5141. nearPhase(result,si.convexPolyhedronRepresentation,sj,xi,xj,qi,qj,bi,bj);
  5142. break;
  5143. default:
  5144. console.warn("Collision between CANNON.Shape.types.BOX and "+sj.type+" not implemented yet.");
  5145. break;
  5146. }
  5147. } else if(si.type===types.COMPOUND){
  5148. switch(sj.type){
  5149. case types.COMPOUND: // compound-compound
  5150. recurseCompound(result,si,sj,xi,xj,qi,qj,bi,bj);
  5151. break;
  5152. case types.CONVEXPOLYHEDRON: // compound-convex polyhedron
  5153. // Must swap
  5154. var r = [];
  5155. recurseCompound(r,sj,si,xj,xi,qj,qi,bj,bi);
  5156. for(var ri=0; ri!==r.length; ri++){
  5157. swapResult(r[ri]);
  5158. result.push(r[ri]);
  5159. }
  5160. break;
  5161. default:
  5162. console.warn("Collision between CANNON.Shape.types.COMPOUND and "+sj.type+" not implemented yet.");
  5163. break;
  5164. }
  5165. } else if(si.type===types.CONVEXPOLYHEDRON){
  5166. switch(sj.type){
  5167. case types.CONVEXPOLYHEDRON: // convex polyhedron - convex polyhedron
  5168. convexConvex(result,si,sj,xi,xj,qi,qj,bi,bj);
  5169. break;
  5170. default:
  5171. console.warn("Collision between CANNON.Shape.types.CONVEXPOLYHEDRON and "+sj.type+" not implemented yet.");
  5172. break;
  5173. }
  5174. }
  5175. } else {
  5176. // Particle!
  5177. switch(sj.type){
  5178. case types.PLANE: // Particle vs plane
  5179. particlePlane(result,si,sj,xi,xj,qi,qj,bi,bj);
  5180. break;
  5181. case types.SPHERE: // Particle vs sphere
  5182. particleSphere(result,si,sj,xi,xj,qi,qj,bi,bj);
  5183. break;
  5184. case types.BOX: // Particle vs box
  5185. particleConvex(result,si,sj.convexPolyhedronRepresentation,xi,xj,qi,qj,bi,bj);
  5186. break;
  5187. case types.CONVEXPOLYHEDRON: // particle-convex
  5188. particleConvex(result,si,sj,xi,xj,qi,qj,bi,bj);
  5189. break;
  5190. case types.COMPOUND: // particle-compound
  5191. recurseCompound(result,si,sj,xi,xj,qi,qj,bi,bj);
  5192. break;
  5193. default:
  5194. console.warn("Collision between CANNON.Particle and "+sj.type+" not implemented yet.");
  5195. break;
  5196. }
  5197. }
  5198. // Swap back if we swapped bodies in the beginning
  5199. for(var i=0, Nresults=result.length; swapped && i!==Nresults; i++){
  5200. swapResult(result[i]);
  5201. }
  5202. }
  5203. /**
  5204. * @method reduceContacts
  5205. * @memberof CANNON.ContactGenerator
  5206. * @brief Removes unnecessary members of an array of CANNON.ContactPoint.
  5207. */
  5208. this.reduceContacts = function(contacts){
  5209. };
  5210. /**
  5211. * @method getContacts
  5212. * @memberof CANNON.ContactGenerator
  5213. * @param array p1 Array of body indices
  5214. * @param array p2 Array of body indices
  5215. * @param CANNON.World world
  5216. * @param array result Array to store generated contacts
  5217. * @param array oldcontacts Optional. Array of reusable contact objects
  5218. */
  5219. this.getContacts = function(p1,p2,world,result,oldcontacts){
  5220. // Save old contact objects
  5221. contactPointPool = oldcontacts;
  5222. for(var k=0, N=p1.length; k!==N; k++){
  5223. // Get current collision indeces
  5224. var bi = p1[k],
  5225. bj = p2[k];
  5226. // Get contacts
  5227. nearPhase( result,
  5228. bi.shape,
  5229. bj.shape,
  5230. bi.position,
  5231. bj.position,
  5232. bi.quaternion,
  5233. bj.quaternion,
  5234. bi,
  5235. bj
  5236. );
  5237. }
  5238. };
  5239. };
  5240. /**
  5241. * @class CANNON.Equation
  5242. * @brief Equation base class
  5243. * @author schteppe
  5244. * @param CANNON.Body bi
  5245. * @param CANNON.Body bj
  5246. * @param float minForce Minimum (read: negative max) force to be applied by the constraint.
  5247. * @param float maxForce Maximum (read: positive max) force to be applied by the constraint.
  5248. */
  5249. CANNON.Equation = function(bi,bj,minForce,maxForce){
  5250. this.id = -1;
  5251. /**
  5252. * @property float minForce
  5253. * @memberof CANNON.Equation
  5254. */
  5255. this.minForce = typeof(minForce)==="undefined" ? -1e6 : minForce;
  5256. /**
  5257. * @property float maxForce
  5258. * @memberof CANNON.Equation
  5259. */
  5260. this.maxForce = typeof(maxForce)==="undefined" ? 1e6 : maxForce;
  5261. /**
  5262. * @property CANNON.Body bi
  5263. * @memberof CANNON.Equation
  5264. */
  5265. this.bi = bi;
  5266. /**
  5267. * @property CANNON.Body bj
  5268. * @memberof CANNON.Equation
  5269. */
  5270. this.bj = bj;
  5271. /**
  5272. * @property float stiffness
  5273. * @brief Corresponds to spring stiffness. Makes constraints stiffer, but harder to solve.
  5274. * @memberof CANNON.Equation
  5275. */
  5276. this.stiffness = 1e7;
  5277. /**
  5278. * @property float regularizationTime
  5279. * @brief Similar to damping. Represents the number of timesteps needed to stabilize the constraint.
  5280. * @memberof CANNON.Equation
  5281. */
  5282. this.regularizationTime = 5;
  5283. /**
  5284. * @property float a
  5285. * @brief SPOOK parameter
  5286. * @memberof CANNON.Equation
  5287. */
  5288. this.a = 0.0;
  5289. /**
  5290. * @property float b
  5291. * @brief SPOOK parameter
  5292. * @memberof CANNON.Equation
  5293. */
  5294. this.b = 0.0;
  5295. /**
  5296. * @property float eps
  5297. * @brief SPOOK parameter
  5298. * @memberof CANNON.Equation
  5299. */
  5300. this.eps = 0.0;
  5301. /**
  5302. * @property bool spookParamsNeedsUpdate
  5303. * @brief Set to true if you just changed stiffness or regularization. The parameters a,b,eps will be recalculated by the solver before solve.
  5304. * @memberof CANNON.Equation
  5305. */
  5306. this.spookParamsNeedsUpdate = true;
  5307. };
  5308. CANNON.Equation.prototype.constructor = CANNON.Equation;
  5309. /**
  5310. * @method updateSpookParams
  5311. * @brief Recalculates a,b,eps.
  5312. * @memberof CANNON.Equation
  5313. */
  5314. CANNON.Equation.prototype.updateSpookParams = function(h){
  5315. var d = this.regularizationTime,
  5316. k = this.stiffness;
  5317. this.a = 4.0 / (h * (1 + 4 * d));
  5318. this.b = (4.0 * d) / (1 + 4 * d);
  5319. this.eps = 4.0 / (h * h * k * (1 + 4 * d));
  5320. };
  5321. /**
  5322. * @class CANNON.ContactEquation
  5323. * @brief Contact/non-penetration constraint equation
  5324. * @author schteppe
  5325. * @param CANNON.Body bj
  5326. * @param CANNON.Body bi
  5327. * @extends CANNON.Equation
  5328. */
  5329. CANNON.ContactEquation = function(bi,bj){
  5330. CANNON.Equation.call(this,bi,bj,0,1e6);
  5331. /**
  5332. * @property float restitution
  5333. * @memberof CANNON.ContactEquation
  5334. */
  5335. this.restitution = 0.0; // "bounciness": u1 = -e*u0
  5336. /**
  5337. * @property CANNON.Vec3 ri
  5338. * @memberof CANNON.ContactEquation
  5339. * @brief World-oriented vector that goes from the center of bi to the contact point in bi.
  5340. */
  5341. this.ri = new CANNON.Vec3();
  5342. /**
  5343. * @property CANNON.Vec3 rj
  5344. * @memberof CANNON.ContactEquation
  5345. */
  5346. this.rj = new CANNON.Vec3();
  5347. this.penetrationVec = new CANNON.Vec3();
  5348. this.ni = new CANNON.Vec3();
  5349. this.rixn = new CANNON.Vec3();
  5350. this.rjxn = new CANNON.Vec3();
  5351. this.invIi = new CANNON.Mat3();
  5352. this.invIj = new CANNON.Mat3();
  5353. // Cache
  5354. this.biInvInertiaTimesRixn = new CANNON.Vec3();
  5355. this.bjInvInertiaTimesRjxn = new CANNON.Vec3();
  5356. };
  5357. CANNON.ContactEquation.prototype = new CANNON.Equation();
  5358. CANNON.ContactEquation.prototype.constructor = CANNON.ContactEquation;
  5359. /**
  5360. * @method reset
  5361. * @memberof CANNON.ContactEquation
  5362. * @brief To be run before object reuse
  5363. */
  5364. CANNON.ContactEquation.prototype.reset = function(){
  5365. this.invInertiaTimesRxnNeedsUpdate = true;
  5366. };
  5367. var ContactEquation_computeB_temp1 = new CANNON.Vec3(); // Temp vectors
  5368. var ContactEquation_computeB_temp2 = new CANNON.Vec3();
  5369. var ContactEquation_computeB_zero = new CANNON.Vec3();
  5370. CANNON.ContactEquation.prototype.computeB = function(h){
  5371. var a = this.a,
  5372. b = this.b;
  5373. var bi = this.bi;
  5374. var bj = this.bj;
  5375. var ri = this.ri;
  5376. var rj = this.rj;
  5377. var rixn = this.rixn;
  5378. var rjxn = this.rjxn;
  5379. var zero = ContactEquation_computeB_zero;
  5380. var vi = bi.velocity;
  5381. var wi = bi.angularVelocity ? bi.angularVelocity : zero;
  5382. var fi = bi.force;
  5383. var taui = bi.tau ? bi.tau : zero;
  5384. var vj = bj.velocity;
  5385. var wj = bj.angularVelocity ? bj.angularVelocity : zero;
  5386. var fj = bj.force;
  5387. var tauj = bj.tau ? bj.tau : zero;
  5388. var penetrationVec = this.penetrationVec;
  5389. var invMassi = bi.invMass;
  5390. var invMassj = bj.invMass;
  5391. var invIi = this.invIi;
  5392. var invIj = this.invIj;
  5393. if(bi.invInertia){
  5394. invIi.setTrace(bi.invInertia);
  5395. } else {
  5396. invIi.identity(); // ok?
  5397. }
  5398. if(bj.invInertia){
  5399. invIj.setTrace(bj.invInertia);
  5400. } else {
  5401. invIj.identity(); // ok?
  5402. }
  5403. var n = this.ni;
  5404. // Caluclate cross products
  5405. ri.cross(n,rixn);
  5406. rj.cross(n,rjxn);
  5407. // Calculate q = xj+rj -(xi+ri) i.e. the penetration vector
  5408. var penetrationVec = this.penetrationVec;
  5409. penetrationVec.set(0,0,0);
  5410. penetrationVec.vadd(bj.position,penetrationVec);
  5411. penetrationVec.vadd(rj,penetrationVec);
  5412. penetrationVec.vsub(bi.position,penetrationVec);
  5413. penetrationVec.vsub(ri,penetrationVec);
  5414. var Gq = n.dot(penetrationVec);//-Math.abs(this.penetration);
  5415. var invIi_vmult_taui = ContactEquation_computeB_temp1;
  5416. var invIj_vmult_tauj = ContactEquation_computeB_temp2;
  5417. invIi.vmult(taui,invIi_vmult_taui);
  5418. invIj.vmult(tauj,invIj_vmult_tauj);
  5419. // Compute iteration
  5420. var ePlusOne = this.restitution+1;
  5421. var GW = ePlusOne*vj.dot(n) - ePlusOne*vi.dot(n) + wj.dot(rjxn) - wi.dot(rixn);
  5422. var GiMf = fj.dot(n)*invMassj - fi.dot(n)*invMassi + rjxn.dot(invIj_vmult_tauj) - rixn.dot(invIi_vmult_taui);
  5423. var B = - Gq * a - GW * b - h*GiMf;
  5424. return B;
  5425. };
  5426. // Compute C = GMG+eps in the SPOOK equation
  5427. var computeC_temp1 = new CANNON.Vec3();
  5428. var computeC_temp2 = new CANNON.Vec3();
  5429. CANNON.ContactEquation.prototype.computeC = function(){
  5430. var bi = this.bi;
  5431. var bj = this.bj;
  5432. var rixn = this.rixn;
  5433. var rjxn = this.rjxn;
  5434. var invMassi = bi.invMass;
  5435. var invMassj = bj.invMass;
  5436. var C = invMassi + invMassj + this.eps;
  5437. var invIi = this.invIi;
  5438. var invIj = this.invIj;
  5439. /*
  5440. if(bi.invInertia){
  5441. invIi.setTrace(bi.invInertia);
  5442. } else {
  5443. invIi.identity(); // ok?
  5444. }
  5445. if(bj.invInertia){
  5446. invIj.setTrace(bj.invInertia);
  5447. } else {
  5448. invIj.identity(); // ok?
  5449. }
  5450. */
  5451. // Compute rxn * I * rxn for each body
  5452. invIi.vmult(rixn, this.biInvInertiaTimesRixn);
  5453. invIj.vmult(rjxn, this.bjInvInertiaTimesRjxn);
  5454. /*
  5455. invIi.vmult(rixn,computeC_temp1);
  5456. invIj.vmult(rjxn,computeC_temp2);
  5457. C += computeC_temp1.dot(rixn);
  5458. C += computeC_temp2.dot(rjxn);
  5459. */
  5460. C += this.biInvInertiaTimesRixn.dot(rixn);
  5461. C += this.bjInvInertiaTimesRjxn.dot(rjxn);
  5462. return C;
  5463. };
  5464. var computeGWlambda_ulambda = new CANNON.Vec3();
  5465. CANNON.ContactEquation.prototype.computeGWlambda = function(){
  5466. var bi = this.bi;
  5467. var bj = this.bj;
  5468. var ulambda = computeGWlambda_ulambda;
  5469. var GWlambda = 0.0;
  5470. bj.vlambda.vsub(bi.vlambda, ulambda);
  5471. GWlambda += ulambda.dot(this.ni);
  5472. // Angular
  5473. if(bi.wlambda){
  5474. GWlambda -= bi.wlambda.dot(this.rixn);
  5475. }
  5476. if(bj.wlambda){
  5477. GWlambda += bj.wlambda.dot(this.rjxn);
  5478. }
  5479. return GWlambda;
  5480. };
  5481. var ContactEquation_addToWlambda_temp1 = new CANNON.Vec3();
  5482. var ContactEquation_addToWlambda_temp2 = new CANNON.Vec3();
  5483. CANNON.ContactEquation.prototype.addToWlambda = function(deltalambda){
  5484. var bi = this.bi,
  5485. bj = this.bj,
  5486. rixn = this.rixn,
  5487. rjxn = this.rjxn,
  5488. invMassi = bi.invMass,
  5489. invMassj = bj.invMass,
  5490. n = this.ni,
  5491. temp1 = ContactEquation_addToWlambda_temp1,
  5492. temp2 = ContactEquation_addToWlambda_temp2;
  5493. // Add to linear velocity
  5494. n.mult(invMassi * deltalambda, temp2);
  5495. bi.vlambda.vsub(temp2,bi.vlambda);
  5496. n.mult(invMassj * deltalambda, temp2);
  5497. bj.vlambda.vadd(temp2,bj.vlambda);
  5498. // Add to angular velocity
  5499. if(bi.wlambda !== undefined){
  5500. this.biInvInertiaTimesRixn.mult(deltalambda,temp1);
  5501. bi.wlambda.vsub(temp1,bi.wlambda);
  5502. }
  5503. if(bj.wlambda !== undefined){
  5504. this.bjInvInertiaTimesRjxn.mult(deltalambda,temp1);
  5505. bj.wlambda.vadd(temp1,bj.wlambda);
  5506. }
  5507. };
  5508. /**
  5509. * @class CANNON.FrictionEquation
  5510. * @brief Constrains the slipping in a contact along a tangent
  5511. * @author schteppe
  5512. * @param CANNON.Body bi
  5513. * @param CANNON.Body bj
  5514. * @param float slipForce should be +-F_friction = +-mu * F_normal = +-mu * m * g
  5515. * @extends CANNON.Equation
  5516. */
  5517. CANNON.FrictionEquation = function(bi,bj,slipForce){
  5518. CANNON.Equation.call(this,bi,bj,-slipForce,slipForce);
  5519. this.ri = new CANNON.Vec3();
  5520. this.rj = new CANNON.Vec3();
  5521. this.t = new CANNON.Vec3(); // tangent
  5522. // The following is just cache
  5523. this.rixt = new CANNON.Vec3();
  5524. this.rjxt = new CANNON.Vec3();
  5525. this.wixri = new CANNON.Vec3();
  5526. this.wjxrj = new CANNON.Vec3();
  5527. this.invIi = new CANNON.Mat3();
  5528. this.invIj = new CANNON.Mat3();
  5529. this.relVel = new CANNON.Vec3();
  5530. this.relForce = new CANNON.Vec3();
  5531. this.biInvInertiaTimesRixt = new CANNON.Vec3();
  5532. this.bjInvInertiaTimesRjxt = new CANNON.Vec3();
  5533. };
  5534. CANNON.FrictionEquation.prototype = new CANNON.Equation();
  5535. CANNON.FrictionEquation.prototype.constructor = CANNON.FrictionEquation;
  5536. var FrictionEquation_computeB_temp1 = new CANNON.Vec3();
  5537. var FrictionEquation_computeB_temp2 = new CANNON.Vec3();
  5538. var FrictionEquation_computeB_zero = new CANNON.Vec3();
  5539. CANNON.FrictionEquation.prototype.computeB = function(h){
  5540. var a = this.a,
  5541. b = this.b,
  5542. bi = this.bi,
  5543. bj = this.bj,
  5544. ri = this.ri,
  5545. rj = this.rj,
  5546. rixt = this.rixt,
  5547. rjxt = this.rjxt,
  5548. wixri = this.wixri,
  5549. wjxrj = this.wjxrj,
  5550. zero = FrictionEquation_computeB_zero;
  5551. var vi = bi.velocity,
  5552. wi = bi.angularVelocity ? bi.angularVelocity : zero,
  5553. fi = bi.force,
  5554. taui = bi.tau ? bi.tau : zero,
  5555. vj = bj.velocity,
  5556. wj = bj.angularVelocity ? bj.angularVelocity : zero,
  5557. fj = bj.force,
  5558. tauj = bj.tau ? bj.tau : zero,
  5559. relVel = this.relVel,
  5560. relForce = this.relForce,
  5561. invMassi = bi.invMass,
  5562. invMassj = bj.invMass,
  5563. invIi = this.invIi,
  5564. invIj = this.invIj,
  5565. t = this.t,
  5566. invIi_vmult_taui = FrictionEquation_computeB_temp1,
  5567. invIj_vmult_tauj = FrictionEquation_computeB_temp2;
  5568. if(bi.invInertia){
  5569. invIi.setTrace(bi.invInertia);
  5570. }
  5571. if(bj.invInertia){
  5572. invIj.setTrace(bj.invInertia);
  5573. }
  5574. // Caluclate cross products
  5575. ri.cross(t,rixt);
  5576. rj.cross(t,rjxt);
  5577. wi.cross(ri,wixri);
  5578. wj.cross(rj,wjxrj);
  5579. invIi.vmult(taui,invIi_vmult_taui);
  5580. invIj.vmult(tauj,invIj_vmult_tauj);
  5581. var Gq = 0; // we do only want to constrain motion
  5582. var GW = vj.dot(t) - vi.dot(t) + wjxrj.dot(t) - wixri.dot(t); // eq. 40
  5583. var GiMf = fj.dot(t)*invMassj - fi.dot(t)*invMassi + rjxt.dot(invIj_vmult_tauj) - rixt.dot(invIi_vmult_taui);
  5584. var B = - Gq * a - GW * b - h*GiMf;
  5585. return B;
  5586. };
  5587. // Compute C = G * Minv * G + eps
  5588. //var FEcomputeC_temp1 = new CANNON.Vec3();
  5589. //var FEcomputeC_temp2 = new CANNON.Vec3();
  5590. CANNON.FrictionEquation.prototype.computeC = function(){
  5591. var bi = this.bi,
  5592. bj = this.bj,
  5593. rixt = this.rixt,
  5594. rjxt = this.rjxt,
  5595. invMassi = bi.invMass,
  5596. invMassj = bj.invMass,
  5597. C = invMassi + invMassj + this.eps,
  5598. invIi = this.invIi,
  5599. invIj = this.invIj;
  5600. /*
  5601. if(bi.invInertia){
  5602. invIi.setTrace(bi.invInertia);
  5603. }
  5604. if(bj.invInertia){
  5605. invIj.setTrace(bj.invInertia);
  5606. }
  5607. */
  5608. // Compute rxt * I * rxt for each body
  5609. /*
  5610. invIi.vmult(rixt,FEcomputeC_temp1);
  5611. invIj.vmult(rjxt,FEcomputeC_temp2);
  5612. C += FEcomputeC_temp1.dot(rixt);
  5613. C += FEcomputeC_temp2.dot(rjxt);
  5614. */
  5615. invIi.vmult(rixt,this.biInvInertiaTimesRixt);
  5616. invIj.vmult(rjxt,this.bjInvInertiaTimesRjxt);
  5617. C += this.biInvInertiaTimesRixt.dot(rixt);
  5618. C += this.bjInvInertiaTimesRjxt.dot(rjxt);
  5619. return C;
  5620. };
  5621. var FrictionEquation_computeGWlambda_ulambda = new CANNON.Vec3();
  5622. CANNON.FrictionEquation.prototype.computeGWlambda = function(){
  5623. // Correct at all ???
  5624. var bi = this.bi;
  5625. var bj = this.bj;
  5626. var GWlambda = 0.0;
  5627. var ulambda = FrictionEquation_computeGWlambda_ulambda;
  5628. bj.vlambda.vsub(bi.vlambda,ulambda);
  5629. GWlambda += ulambda.dot(this.t);
  5630. // Angular
  5631. if(bi.wlambda){
  5632. GWlambda -= bi.wlambda.dot(this.rixt);
  5633. }
  5634. if(bj.wlambda){
  5635. GWlambda += bj.wlambda.dot(this.rjxt);
  5636. }
  5637. return GWlambda;
  5638. };
  5639. var FrictionEquation_addToWlambda_tmp = new CANNON.Vec3();
  5640. CANNON.FrictionEquation.prototype.addToWlambda = function(deltalambda){
  5641. var bi = this.bi,
  5642. bj = this.bj,
  5643. rixt = this.rixt,
  5644. rjxt = this.rjxt,
  5645. invMassi = bi.invMass,
  5646. invMassj = bj.invMass,
  5647. t = this.t,
  5648. tmp = FrictionEquation_addToWlambda_tmp,
  5649. wi = bi.wlambda,
  5650. wj = bj.wlambda;
  5651. // Add to linear velocity
  5652. t.mult(invMassi * deltalambda, tmp);
  5653. bi.vlambda.vsub(tmp,bi.vlambda);
  5654. t.mult(invMassj * deltalambda, tmp);
  5655. bj.vlambda.vadd(tmp,bj.vlambda);
  5656. // Add to angular velocity
  5657. if(wi){
  5658. /*
  5659. var I = this.invIi;
  5660. I.vmult(rixt,tmp);
  5661. tmp.mult(deltalambda,tmp);
  5662. */
  5663. this.biInvInertiaTimesRixt.mult(deltalambda,tmp);
  5664. wi.vsub(tmp,wi);
  5665. }
  5666. if(wj){
  5667. /*
  5668. var I = this.invIj;
  5669. I.vmult(rjxt,tmp);
  5670. tmp.mult(deltalambda,tmp);
  5671. */
  5672. this.bjInvInertiaTimesRjxt.mult(deltalambda,tmp);
  5673. wj.vadd(tmp,wj);
  5674. }
  5675. };
  5676. /**
  5677. * @class CANNON.RotationalEquation
  5678. * @brief Rotational constraint. Works to keep the local vectors orthogonal to each other.
  5679. * @author schteppe
  5680. * @param CANNON.RigidBody bj
  5681. * @param CANNON.Vec3 localVectorInBodyA
  5682. * @param CANNON.RigidBody bi
  5683. * @param CANNON.Vec3 localVectorInBodyB
  5684. * @extends CANNON.Equation
  5685. */
  5686. CANNON.RotationalEquation = function(bodyA, bodyB){
  5687. CANNON.Equation.call(this,bodyA,bodyB,-1e6,1e6);
  5688. this.ni = new CANNON.Vec3(); // World oriented localVectorInBodyA
  5689. this.nj = new CANNON.Vec3(); // ...and B
  5690. this.nixnj = new CANNON.Vec3();
  5691. this.njxni = new CANNON.Vec3();
  5692. this.invIi = new CANNON.Mat3();
  5693. this.invIj = new CANNON.Mat3();
  5694. this.relVel = new CANNON.Vec3();
  5695. this.relForce = new CANNON.Vec3();
  5696. };
  5697. CANNON.RotationalEquation.prototype = new CANNON.Equation();
  5698. CANNON.RotationalEquation.prototype.constructor = CANNON.RotationalEquation;
  5699. CANNON.RotationalEquation.prototype.computeB = function(h){
  5700. var a = this.a,
  5701. b = this.b;
  5702. var bi = this.bi;
  5703. var bj = this.bj;
  5704. var ni = this.ni;
  5705. var nj = this.nj;
  5706. var nixnj = this.nixnj;
  5707. var njxni = this.njxni;
  5708. var vi = bi.velocity;
  5709. var wi = bi.angularVelocity ? bi.angularVelocity : new CANNON.Vec3();
  5710. var fi = bi.force;
  5711. var taui = bi.tau ? bi.tau : new CANNON.Vec3();
  5712. var vj = bj.velocity;
  5713. var wj = bj.angularVelocity ? bj.angularVelocity : new CANNON.Vec3();
  5714. var fj = bj.force;
  5715. var tauj = bj.tau ? bj.tau : new CANNON.Vec3();
  5716. var invMassi = bi.invMass;
  5717. var invMassj = bj.invMass;
  5718. var invIi = this.invIi;
  5719. var invIj = this.invIj;
  5720. if(bi.invInertia){
  5721. invIi.setTrace(bi.invInertia);
  5722. } else {
  5723. invIi.identity(); // ok?
  5724. }
  5725. if(bj.invInertia) {
  5726. invIj.setTrace(bj.invInertia);
  5727. } else {
  5728. invIj.identity(); // ok?
  5729. }
  5730. // Caluclate cross products
  5731. ni.cross(nj,nixnj);
  5732. nj.cross(ni,njxni);
  5733. // g = ni * nj
  5734. // gdot = (nj x ni) * wi + (ni x nj) * wj
  5735. // G = [0 njxni 0 nixnj]
  5736. // W = [vi wi vj wj]
  5737. var Gq = -ni.dot(nj);
  5738. var GW = njxni.dot(wi) + nixnj.dot(wj);
  5739. var GiMf = 0;//njxni.dot(invIi.vmult(taui)) + nixnj.dot(invIj.vmult(tauj));
  5740. var B = - Gq * a - GW * b - h*GiMf;
  5741. return B;
  5742. };
  5743. // Compute C = GMG+eps
  5744. CANNON.RotationalEquation.prototype.computeC = function(){
  5745. var bi = this.bi;
  5746. var bj = this.bj;
  5747. var nixnj = this.nixnj;
  5748. var njxni = this.njxni;
  5749. var invMassi = bi.invMass;
  5750. var invMassj = bj.invMass;
  5751. var C = /*invMassi + invMassj +*/ this.eps;
  5752. var invIi = this.invIi;
  5753. var invIj = this.invIj;
  5754. if(bi.invInertia){
  5755. invIi.setTrace(bi.invInertia);
  5756. } else {
  5757. invIi.identity(); // ok?
  5758. }
  5759. if(bj.invInertia){
  5760. invIj.setTrace(bj.invInertia);
  5761. } else {
  5762. invIj.identity(); // ok?
  5763. }
  5764. C += invIi.vmult(njxni).dot(njxni);
  5765. C += invIj.vmult(nixnj).dot(nixnj);
  5766. return C;
  5767. };
  5768. var computeGWlambda_ulambda = new CANNON.Vec3();
  5769. CANNON.RotationalEquation.prototype.computeGWlambda = function(){
  5770. var bi = this.bi;
  5771. var bj = this.bj;
  5772. var ulambda = computeGWlambda_ulambda;
  5773. var GWlambda = 0.0;
  5774. //bj.vlambda.vsub(bi.vlambda, ulambda);
  5775. //GWlambda += ulambda.dot(this.ni);
  5776. // Angular
  5777. if(bi.wlambda){
  5778. GWlambda += bi.wlambda.dot(this.njxni);
  5779. }
  5780. if(bj.wlambda){
  5781. GWlambda += bj.wlambda.dot(this.nixnj);
  5782. }
  5783. //console.log("GWlambda:",GWlambda);
  5784. return GWlambda;
  5785. };
  5786. CANNON.RotationalEquation.prototype.addToWlambda = function(deltalambda){
  5787. var bi = this.bi;
  5788. var bj = this.bj;
  5789. var nixnj = this.nixnj;
  5790. var njxni = this.njxni;
  5791. var invMassi = bi.invMass;
  5792. var invMassj = bj.invMass;
  5793. // Add to linear velocity
  5794. //bi.vlambda.vsub(n.mult(invMassi * deltalambda),bi.vlambda);
  5795. //bj.vlambda.vadd(n.mult(invMassj * deltalambda),bj.vlambda);
  5796. // Add to angular velocity
  5797. if(bi.wlambda){
  5798. var I = this.invIi;
  5799. bi.wlambda.vsub(I.vmult(nixnj).mult(deltalambda),bi.wlambda);
  5800. }
  5801. if(bj.wlambda){
  5802. var I = this.invIj;
  5803. bj.wlambda.vadd(I.vmult(nixnj).mult(deltalambda),bj.wlambda);
  5804. }
  5805. };
  5806. /**
  5807. * @class CANNON.Constraint
  5808. * @brief Constraint base class
  5809. * @author schteppe
  5810. * @param CANNON.Body bodyA
  5811. * @param CANNON.Body bodyB
  5812. */
  5813. CANNON.Constraint = function(bodyA,bodyB){
  5814. /**
  5815. * @property Array equations
  5816. * @memberOf CANNON.Constraint
  5817. * @brief Equations to be solved in this constraint
  5818. */
  5819. this.equations = [];
  5820. /**
  5821. * @property CANNON.Body bodyA
  5822. * @memberOf CANNON.Constraint
  5823. */
  5824. this.bodyA = bodyA;
  5825. /**
  5826. * @property CANNON.Body bodyB
  5827. * @memberOf CANNON.Constraint
  5828. */
  5829. this.bodyB = bodyB;
  5830. };
  5831. /**
  5832. * @method update
  5833. * @memberOf CANNON.Constraint
  5834. */
  5835. CANNON.Constraint.prototype.update = function(){
  5836. throw new Error("method update() not implmemented in this Constraint subclass!");
  5837. };
  5838. /**
  5839. * @class CANNON.DistanceConstraint
  5840. * @brief Constrains two bodies to be at a constant distance from each other.
  5841. * @author schteppe
  5842. * @param CANNON.Body bodyA
  5843. * @param CANNON.Body bodyB
  5844. * @param float distance
  5845. * @param float maxForce
  5846. */
  5847. CANNON.DistanceConstraint = function(bodyA,bodyB,distance,maxForce){
  5848. CANNON.Constraint.call(this,bodyA,bodyB);
  5849. if(typeof(maxForce)==="undefined" ) {
  5850. maxForce = 1e6;
  5851. }
  5852. // Equations to be fed to the solver
  5853. var eqs = this.equations = [
  5854. new CANNON.ContactEquation(bodyA,bodyB), // Just in the normal direction
  5855. ];
  5856. var normal = eqs[0];
  5857. normal.minForce = -maxForce;
  5858. normal.maxForce = maxForce;
  5859. // Update
  5860. this.update = function(){
  5861. bodyB.position.vsub(bodyA.position,normal.ni);
  5862. normal.ni.normalize();
  5863. /*bodyA.quaternion.vmult(pivotA,normal.ri);
  5864. bodyB.quaternion.vmult(pivotB,normal.rj);*/
  5865. normal.ni.mult( distance*0.5,normal.ri);
  5866. normal.ni.mult( -distance*0.5,normal.rj);
  5867. };
  5868. };
  5869. CANNON.DistanceConstraint.prototype = new CANNON.Constraint();
  5870. /**
  5871. * @class CANNON.RotationalMotorEquation
  5872. * @brief Rotational motor constraint. Works to keep the relative angular velocity of the bodies to a given value
  5873. * @author schteppe
  5874. * @param CANNON.RigidBody bodyA
  5875. * @param CANNON.RigidBody bodyB
  5876. * @extends CANNON.Equation
  5877. */
  5878. CANNON.RotationalMotorEquation = function(bodyA, bodyB, maxForce){
  5879. maxForce = maxForce || 1e6;
  5880. CANNON.Equation.call(this,bodyA,bodyB,-maxForce,maxForce);
  5881. this.axisA = new CANNON.Vec3(); // World oriented rotational axis
  5882. this.axisB = new CANNON.Vec3(); // World oriented rotational axis
  5883. this.invIi = new CANNON.Mat3();
  5884. this.invIj = new CANNON.Mat3();
  5885. this.targetVelocity = 0;
  5886. };
  5887. CANNON.RotationalMotorEquation.prototype = new CANNON.Equation();
  5888. CANNON.RotationalMotorEquation.prototype.constructor = CANNON.RotationalMotorEquation;
  5889. CANNON.RotationalMotorEquation.prototype.computeB = function(h){
  5890. var a = this.a,
  5891. b = this.b;
  5892. var bi = this.bi;
  5893. var bj = this.bj;
  5894. var axisA = this.axisA;
  5895. var axisB = this.axisB;
  5896. var vi = bi.velocity;
  5897. var wi = bi.angularVelocity ? bi.angularVelocity : new CANNON.Vec3();
  5898. var fi = bi.force;
  5899. var taui = bi.tau ? bi.tau : new CANNON.Vec3();
  5900. var vj = bj.velocity;
  5901. var wj = bj.angularVelocity ? bj.angularVelocity : new CANNON.Vec3();
  5902. var fj = bj.force;
  5903. var tauj = bj.tau ? bj.tau : new CANNON.Vec3();
  5904. var invMassi = bi.invMass;
  5905. var invMassj = bj.invMass;
  5906. var invIi = this.invIi;
  5907. var invIj = this.invIj;
  5908. if(bi.invInertia){
  5909. invIi.setTrace(bi.invInertia);
  5910. } else {
  5911. invIi.identity(); // ok?
  5912. }
  5913. if(bj.invInertia){
  5914. invIj.setTrace(bj.invInertia);
  5915. } else {
  5916. invIj.identity(); // ok?
  5917. }
  5918. // g = 0
  5919. // gdot = axisA * wi - axisB * wj
  5920. // G = [0 axisA 0 -axisB]
  5921. // W = [vi wi vj wj]
  5922. var Gq = 0;
  5923. var GW = axisA.dot(wi) + axisB.dot(wj) + this.targetVelocity;
  5924. var GiMf = 0;//axis.dot(invIi.vmult(taui)) + axis.dot(invIj.vmult(tauj));
  5925. var B = - Gq * a - GW * b - h*GiMf;
  5926. return B;
  5927. };
  5928. // Compute C = GMG+eps
  5929. CANNON.RotationalMotorEquation.prototype.computeC = function(){
  5930. var bi = this.bi;
  5931. var bj = this.bj;
  5932. var axisA = this.axisA;
  5933. var axisB = this.axisB;
  5934. var invMassi = bi.invMass;
  5935. var invMassj = bj.invMass;
  5936. var C = this.eps;
  5937. var invIi = this.invIi;
  5938. var invIj = this.invIj;
  5939. if(bi.invInertia){
  5940. invIi.setTrace(bi.invInertia);
  5941. } else {
  5942. invIi.identity(); // ok?
  5943. }
  5944. if(bj.invInertia){
  5945. invIj.setTrace(bj.invInertia);
  5946. } else {
  5947. invIj.identity(); // ok?
  5948. }
  5949. C += invIi.vmult(axisA).dot(axisB);
  5950. C += invIj.vmult(axisB).dot(axisB);
  5951. return C;
  5952. };
  5953. var computeGWlambda_ulambda = new CANNON.Vec3();
  5954. CANNON.RotationalMotorEquation.prototype.computeGWlambda = function(){
  5955. var bi = this.bi;
  5956. var bj = this.bj;
  5957. var ulambda = computeGWlambda_ulambda;
  5958. var axisA = this.axisA;
  5959. var axisB = this.axisB;
  5960. var GWlambda = 0.0;
  5961. //bj.vlambda.vsub(bi.vlambda, ulambda);
  5962. //GWlambda += ulambda.dot(this.ni);
  5963. // Angular
  5964. if(bi.wlambda){
  5965. GWlambda += bi.wlambda.dot(axisA);
  5966. }
  5967. if(bj.wlambda){
  5968. GWlambda += bj.wlambda.dot(axisB);
  5969. }
  5970. //console.log("GWlambda:",GWlambda);
  5971. return GWlambda;
  5972. };
  5973. CANNON.RotationalMotorEquation.prototype.addToWlambda = function(deltalambda){
  5974. var bi = this.bi;
  5975. var bj = this.bj;
  5976. var axisA = this.axisA;
  5977. var axisB = this.axisB;
  5978. var invMassi = bi.invMass;
  5979. var invMassj = bj.invMass;
  5980. // Add to linear velocity
  5981. //bi.vlambda.vsub(n.mult(invMassi * deltalambda),bi.vlambda);
  5982. //bj.vlambda.vadd(n.mult(invMassj * deltalambda),bj.vlambda);
  5983. // Add to angular velocity
  5984. if(bi.wlambda){
  5985. var I = this.invIi;
  5986. bi.wlambda.vsub(I.vmult(axisA).mult(deltalambda),bi.wlambda);
  5987. }
  5988. if(bj.wlambda){
  5989. var I = this.invIj;
  5990. bj.wlambda.vadd(I.vmult(axisB).mult(deltalambda),bj.wlambda);
  5991. }
  5992. };
  5993. /**
  5994. * @class CANNON.HingeConstraint
  5995. * @brief Hinge constraint. Tries to keep the local body axes equal.
  5996. * @author schteppe
  5997. * @param CANNON.RigidBody bodyA
  5998. * @param CANNON.Vec3 pivotA A point defined locally in bodyA. This defines the offset of axisA.
  5999. * @param CANNON.Vec3 axisA an axis that bodyA can rotate around.
  6000. * @param CANNON.RigidBody bodyB
  6001. * @param CANNON.Vec3 pivotB
  6002. * @param CANNON.Vec3 axisB
  6003. * @param float maxForce
  6004. */
  6005. CANNON.HingeConstraint = function(bodyA, pivotA, axisA, bodyB, pivotB, axisB, maxForce){
  6006. CANNON.Constraint.call(this,bodyA,bodyB);
  6007. maxForce = maxForce || 1e6;
  6008. var that = this;
  6009. // Equations to be fed to the solver
  6010. var eqs = this.equations = [
  6011. new CANNON.RotationalEquation(bodyA,bodyB), // rotational1
  6012. new CANNON.RotationalEquation(bodyA,bodyB), // rotational2
  6013. new CANNON.ContactEquation(bodyA,bodyB), // p2pNormal
  6014. new CANNON.ContactEquation(bodyA,bodyB), // p2pTangent1
  6015. new CANNON.ContactEquation(bodyA,bodyB), // p2pTangent2
  6016. ];
  6017. this.getRotationalEquation1 = function(){ return eqs[0]; };
  6018. this.getRotationalEquation2 = function(){ return eqs[1]; };
  6019. this.getPointToPointEquation1 = function(){ return eqs[2]; };
  6020. this.getPointToPointEquation2 = function(){ return eqs[3]; };
  6021. this.getPointToPointEquation3 = function(){ return eqs[4]; };
  6022. var r1 = this.getRotationalEquation1();
  6023. var r2 = this.getRotationalEquation2();
  6024. var normal = this.getPointToPointEquation1();
  6025. var t1 = this.getPointToPointEquation2();
  6026. var t2 = this.getPointToPointEquation3();
  6027. var motor; // not activated by default
  6028. t1.minForce = t2.minForce = normal.minForce = -maxForce;
  6029. t1.maxForce = t2.maxForce = normal.maxForce = maxForce;
  6030. var unitPivotA = pivotA.unit();
  6031. var unitPivotB = pivotB.unit();
  6032. var axisA_x_pivotA = new CANNON.Vec3();
  6033. var axisA_x_axisA_x_pivotA = new CANNON.Vec3();
  6034. var axisB_x_pivotB = new CANNON.Vec3();
  6035. axisA.cross(unitPivotA,axisA_x_pivotA);
  6036. axisA.cross(axisA_x_pivotA,axisA_x_axisA_x_pivotA);
  6037. axisB.cross(unitPivotB,axisB_x_pivotB);
  6038. axisA_x_pivotA.normalize();
  6039. axisB_x_pivotB.normalize();
  6040. // Motor stuff
  6041. var motorEnabled = false;
  6042. this.motorTargetVelocity = 0;
  6043. this.motorMinForce = -maxForce;
  6044. this.motorMaxForce = maxForce;
  6045. this.enableMotor = function(){
  6046. if(!motorEnabled){
  6047. motor = new CANNON.RotationalMotorEquation(bodyA,bodyB,maxForce);
  6048. eqs.push(motor);
  6049. motorEnabled = true;
  6050. }
  6051. };
  6052. this.disableMotor = function(){
  6053. if(motorEnabled){
  6054. motorEnabled = false;
  6055. motor = null;
  6056. eqs.pop();
  6057. }
  6058. };
  6059. // Update
  6060. this.update = function(){
  6061. // Update world positions of pivots
  6062. /*
  6063. bodyB.position.vsub(bodyA.position,normal.ni);
  6064. normal.ni.normalize();
  6065. */
  6066. normal.ni.set(1,0,0);
  6067. t1.ni.set(0,1,0);
  6068. t2.ni.set(0,0,1);
  6069. bodyA.quaternion.vmult(pivotA,normal.ri);
  6070. bodyB.quaternion.vmult(pivotB,normal.rj);
  6071. //normal.ni.tangents(t1.ni,t2.ni);
  6072. normal.ri.copy(t1.ri);
  6073. normal.rj.copy(t1.rj);
  6074. normal.ri.copy(t2.ri);
  6075. normal.rj.copy(t2.rj);
  6076. // update rotational constraints
  6077. bodyA.quaternion.vmult(axisA_x_pivotA, r1.ni);
  6078. bodyB.quaternion.vmult(axisB, r1.nj);
  6079. bodyA.quaternion.vmult(axisA_x_axisA_x_pivotA, r2.ni);
  6080. bodyB.quaternion.vmult(axisB, r2.nj);
  6081. if(motorEnabled){
  6082. bodyA.quaternion.vmult(axisA,motor.axisA);
  6083. bodyB.quaternion.vmult(axisB,motor.axisB);
  6084. motor.targetVelocity = that.motorTargetVelocity;
  6085. motor.maxForce = that.motorMaxForce;
  6086. motor.minForce = that.motorMinForce;
  6087. }
  6088. };
  6089. };
  6090. CANNON.HingeConstraint.prototype = new CANNON.Constraint();
  6091. /**
  6092. * @class CANNON.PointToPointConstraint
  6093. * @brief Connects two bodies at given offset points
  6094. * @author schteppe
  6095. * @param CANNON.Body bodyA
  6096. * @param CANNON.Vec3 pivotA The point relative to the center of mass of bodyA which bodyA is constrained to.
  6097. * @param CANNON.Body bodyB Body that will be constrained in a similar way to the same point as bodyA. We will therefore get sort of a link between bodyA and bodyB. If not specified, bodyA will be constrained to a static point.
  6098. * @param CANNON.Vec3 pivotB See pivotA.
  6099. * @param float maxForce The maximum force that should be applied to constrain the bodies.
  6100. * @extends CANNON.Constraint
  6101. */
  6102. CANNON.PointToPointConstraint = function(bodyA,pivotA,bodyB,pivotB,maxForce){
  6103. CANNON.Constraint.call(this,bodyA,bodyB);
  6104. // Equations to be fed to the solver
  6105. var eqs = this.equations = [
  6106. new CANNON.ContactEquation(bodyA,bodyB), // Normal
  6107. new CANNON.ContactEquation(bodyA,bodyB), // Tangent2
  6108. new CANNON.ContactEquation(bodyA,bodyB), // Tangent2
  6109. ];
  6110. var normal = eqs[0];
  6111. var t1 = eqs[1];
  6112. var t2 = eqs[2];
  6113. t1.minForce = t2.minForce = normal.minForce = -maxForce;
  6114. t1.maxForce = t2.maxForce = normal.maxForce = maxForce;
  6115. // Update
  6116. this.update = function(){
  6117. bodyB.position.vsub(bodyA.position,normal.ni);
  6118. normal.ni.normalize();
  6119. bodyA.quaternion.vmult(pivotA,normal.ri);
  6120. bodyB.quaternion.vmult(pivotB,normal.rj);
  6121. normal.ni.tangents(t1.ni,t2.ni);
  6122. normal.ri.copy(t1.ri);
  6123. normal.rj.copy(t1.rj);
  6124. normal.ri.copy(t2.ri);
  6125. normal.rj.copy(t2.rj);
  6126. };
  6127. };
  6128. CANNON.PointToPointConstraint.prototype = new CANNON.Constraint();
  6129. if (typeof module !== 'undefined') {
  6130. // export for node
  6131. module.exports = CANNON;
  6132. } else {
  6133. // assign to window
  6134. this.CANNON = CANNON;
  6135. }
  6136. }).apply(this);