ColladaLoader.js 110 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278
  1. import {
  2. AmbientLight,
  3. AnimationClip,
  4. Bone,
  5. BufferGeometry,
  6. ClampToEdgeWrapping,
  7. Color,
  8. DirectionalLight,
  9. DoubleSide,
  10. Euler,
  11. FileLoader,
  12. Float32BufferAttribute,
  13. FrontSide,
  14. Group,
  15. Line,
  16. LineBasicMaterial,
  17. LineSegments,
  18. Loader,
  19. LoaderUtils,
  20. MathUtils,
  21. Matrix4,
  22. Mesh,
  23. MeshBasicMaterial,
  24. MeshLambertMaterial,
  25. MeshPhongMaterial,
  26. OrthographicCamera,
  27. PerspectiveCamera,
  28. PointLight,
  29. Quaternion,
  30. QuaternionKeyframeTrack,
  31. RepeatWrapping,
  32. Scene,
  33. Skeleton,
  34. SkinnedMesh,
  35. SpotLight,
  36. TextureLoader,
  37. Vector2,
  38. Vector3,
  39. VectorKeyframeTrack,
  40. sRGBEncoding
  41. } from '../lib/three.module.js'
  42. import { TGALoader } from './TGALoader.js'
  43. class ColladaLoader extends Loader {
  44. constructor(manager) {
  45. super(manager)
  46. }
  47. load(url, onLoad, onProgress, onError) {
  48. const scope = this
  49. const path = scope.path === '' ? LoaderUtils.extractUrlBase(url) : scope.path
  50. const loader = new FileLoader(scope.manager)
  51. loader.setPath(scope.path)
  52. loader.setRequestHeader(scope.requestHeader)
  53. loader.setWithCredentials(scope.withCredentials)
  54. loader.load(
  55. url,
  56. function(text) {
  57. try {
  58. onLoad(scope.parse(text, path))
  59. } catch (e) {
  60. if (onError) {
  61. onError(e)
  62. } else {
  63. console.error(e)
  64. }
  65. scope.manager.itemError(url)
  66. }
  67. },
  68. onProgress,
  69. onError
  70. )
  71. }
  72. parse(text, path) {
  73. function getElementsByTagName(xml, name) {
  74. // Non recursive xml.getElementsByTagName() ...
  75. const array = []
  76. const childNodes = xml.childNodes
  77. for (let i = 0, l = childNodes.length; i < l; i++) {
  78. const child = childNodes[i]
  79. if (child.nodeName === name) {
  80. array.push(child)
  81. }
  82. }
  83. return array
  84. }
  85. function parseStrings(text) {
  86. if (text.length === 0) return []
  87. const parts = text.trim().split(/\s+/)
  88. const array = new Array(parts.length)
  89. for (let i = 0, l = parts.length; i < l; i++) {
  90. array[i] = parts[i]
  91. }
  92. return array
  93. }
  94. function parseFloats(text) {
  95. if (text.length === 0) return []
  96. const parts = text.trim().split(/\s+/)
  97. const array = new Array(parts.length)
  98. for (let i = 0, l = parts.length; i < l; i++) {
  99. array[i] = parseFloat(parts[i])
  100. }
  101. return array
  102. }
  103. function parseInts(text) {
  104. if (text.length === 0) return []
  105. const parts = text.trim().split(/\s+/)
  106. const array = new Array(parts.length)
  107. for (let i = 0, l = parts.length; i < l; i++) {
  108. array[i] = parseInt(parts[i])
  109. }
  110. return array
  111. }
  112. function parseId(text) {
  113. return text.substring(1)
  114. }
  115. function generateId() {
  116. return 'three_default_' + count++
  117. }
  118. function isEmpty(object) {
  119. return Object.keys(object).length === 0
  120. }
  121. // asset
  122. function parseAsset(xml) {
  123. return {
  124. unit: parseAssetUnit(getElementsByTagName(xml, 'unit')[0]),
  125. upAxis: parseAssetUpAxis(getElementsByTagName(xml, 'up_axis')[0])
  126. }
  127. }
  128. function parseAssetUnit(xml) {
  129. if (xml !== undefined && xml.hasAttribute('meter') === true) {
  130. return parseFloat(xml.getAttribute('meter'))
  131. } else {
  132. return 1 // default 1 meter
  133. }
  134. }
  135. function parseAssetUpAxis(xml) {
  136. return xml !== undefined ? xml.textContent : 'Y_UP'
  137. }
  138. // library
  139. function parseLibrary(xml, libraryName, nodeName, parser) {
  140. const library = getElementsByTagName(xml, libraryName)[0]
  141. if (library !== undefined) {
  142. const elements = getElementsByTagName(library, nodeName)
  143. for (let i = 0; i < elements.length; i++) {
  144. parser(elements[i])
  145. }
  146. }
  147. }
  148. function buildLibrary(data, builder) {
  149. for (const name in data) {
  150. const object = data[name]
  151. object.build = builder(data[name])
  152. }
  153. }
  154. // get
  155. function getBuild(data, builder) {
  156. if (data.build !== undefined) return data.build
  157. data.build = builder(data)
  158. return data.build
  159. }
  160. // animation
  161. function parseAnimation(xml) {
  162. const data = {
  163. sources: {},
  164. samplers: {},
  165. channels: {}
  166. }
  167. let hasChildren = false
  168. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  169. const child = xml.childNodes[i]
  170. if (child.nodeType !== 1) continue
  171. let id
  172. switch (child.nodeName) {
  173. case 'source':
  174. id = child.getAttribute('id')
  175. data.sources[id] = parseSource(child)
  176. break
  177. case 'sampler':
  178. id = child.getAttribute('id')
  179. data.samplers[id] = parseAnimationSampler(child)
  180. break
  181. case 'channel':
  182. id = child.getAttribute('target')
  183. data.channels[id] = parseAnimationChannel(child)
  184. break
  185. case 'animation':
  186. // hierarchy of related animations
  187. parseAnimation(child)
  188. hasChildren = true
  189. break
  190. default:
  191. console.log(child)
  192. }
  193. }
  194. if (hasChildren === false) {
  195. // since 'id' attributes can be optional, it's necessary to generate a UUID for unqiue assignment
  196. library.animations[xml.getAttribute('id') || MathUtils.generateUUID()] = data
  197. }
  198. }
  199. function parseAnimationSampler(xml) {
  200. const data = {
  201. inputs: {}
  202. }
  203. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  204. const child = xml.childNodes[i]
  205. if (child.nodeType !== 1) continue
  206. switch (child.nodeName) {
  207. case 'input':
  208. const id = parseId(child.getAttribute('source'))
  209. const semantic = child.getAttribute('semantic')
  210. data.inputs[semantic] = id
  211. break
  212. }
  213. }
  214. return data
  215. }
  216. function parseAnimationChannel(xml) {
  217. const data = {}
  218. const target = xml.getAttribute('target')
  219. // parsing SID Addressing Syntax
  220. let parts = target.split('/')
  221. const id = parts.shift()
  222. let sid = parts.shift()
  223. // check selection syntax
  224. const arraySyntax = sid.indexOf('(') !== -1
  225. const memberSyntax = sid.indexOf('.') !== -1
  226. if (memberSyntax) {
  227. // member selection access
  228. parts = sid.split('.')
  229. sid = parts.shift()
  230. data.member = parts.shift()
  231. } else if (arraySyntax) {
  232. // array-access syntax. can be used to express fields in one-dimensional vectors or two-dimensional matrices.
  233. const indices = sid.split('(')
  234. sid = indices.shift()
  235. for (let i = 0; i < indices.length; i++) {
  236. indices[i] = parseInt(indices[i].replace(/\)/, ''))
  237. }
  238. data.indices = indices
  239. }
  240. data.id = id
  241. data.sid = sid
  242. data.arraySyntax = arraySyntax
  243. data.memberSyntax = memberSyntax
  244. data.sampler = parseId(xml.getAttribute('source'))
  245. return data
  246. }
  247. function buildAnimation(data) {
  248. const tracks = []
  249. const channels = data.channels
  250. const samplers = data.samplers
  251. const sources = data.sources
  252. for (const target in channels) {
  253. if (channels.hasOwnProperty(target)) {
  254. const channel = channels[target]
  255. const sampler = samplers[channel.sampler]
  256. const inputId = sampler.inputs.INPUT
  257. const outputId = sampler.inputs.OUTPUT
  258. const inputSource = sources[inputId]
  259. const outputSource = sources[outputId]
  260. const animation = buildAnimationChannel(channel, inputSource, outputSource)
  261. createKeyframeTracks(animation, tracks)
  262. }
  263. }
  264. return tracks
  265. }
  266. function getAnimation(id) {
  267. return getBuild(library.animations[id], buildAnimation)
  268. }
  269. function buildAnimationChannel(channel, inputSource, outputSource) {
  270. const node = library.nodes[channel.id]
  271. const object3D = getNode(node.id)
  272. const transform = node.transforms[channel.sid]
  273. const defaultMatrix = node.matrix.clone().transpose()
  274. let time, stride
  275. let i, il, j, jl
  276. const data = {}
  277. // the collada spec allows the animation of data in various ways.
  278. // depending on the transform type (matrix, translate, rotate, scale), we execute different logic
  279. switch (transform) {
  280. case 'matrix':
  281. for (i = 0, il = inputSource.array.length; i < il; i++) {
  282. time = inputSource.array[i]
  283. stride = i * outputSource.stride
  284. if (data[time] === undefined) data[time] = {}
  285. if (channel.arraySyntax === true) {
  286. const value = outputSource.array[stride]
  287. const index = channel.indices[0] + 4 * channel.indices[1]
  288. data[time][index] = value
  289. } else {
  290. for (j = 0, jl = outputSource.stride; j < jl; j++) {
  291. data[time][j] = outputSource.array[stride + j]
  292. }
  293. }
  294. }
  295. break
  296. case 'translate':
  297. console.warn('THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform)
  298. break
  299. case 'rotate':
  300. console.warn('THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform)
  301. break
  302. case 'scale':
  303. console.warn('THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform)
  304. break
  305. }
  306. const keyframes = prepareAnimationData(data, defaultMatrix)
  307. const animation = {
  308. name: object3D.uuid,
  309. keyframes: keyframes
  310. }
  311. return animation
  312. }
  313. function prepareAnimationData(data, defaultMatrix) {
  314. const keyframes = []
  315. // transfer data into a sortable array
  316. for (const time in data) {
  317. keyframes.push({ time: parseFloat(time), value: data[time] })
  318. }
  319. // ensure keyframes are sorted by time
  320. keyframes.sort(ascending)
  321. // now we clean up all animation data, so we can use them for keyframe tracks
  322. for (let i = 0; i < 16; i++) {
  323. transformAnimationData(keyframes, i, defaultMatrix.elements[i])
  324. }
  325. return keyframes
  326. // array sort function
  327. function ascending(a, b) {
  328. return a.time - b.time
  329. }
  330. }
  331. const position = new Vector3()
  332. const scale = new Vector3()
  333. const quaternion = new Quaternion()
  334. function createKeyframeTracks(animation, tracks) {
  335. const keyframes = animation.keyframes
  336. const name = animation.name
  337. const times = []
  338. const positionData = []
  339. const quaternionData = []
  340. const scaleData = []
  341. for (let i = 0, l = keyframes.length; i < l; i++) {
  342. const keyframe = keyframes[i]
  343. const time = keyframe.time
  344. const value = keyframe.value
  345. matrix.fromArray(value).transpose()
  346. matrix.decompose(position, quaternion, scale)
  347. times.push(time)
  348. positionData.push(position.x, position.y, position.z)
  349. quaternionData.push(quaternion.x, quaternion.y, quaternion.z, quaternion.w)
  350. scaleData.push(scale.x, scale.y, scale.z)
  351. }
  352. if (positionData.length > 0) tracks.push(new VectorKeyframeTrack(name + '.position', times, positionData))
  353. if (quaternionData.length > 0) tracks.push(new QuaternionKeyframeTrack(name + '.quaternion', times, quaternionData))
  354. if (scaleData.length > 0) tracks.push(new VectorKeyframeTrack(name + '.scale', times, scaleData))
  355. return tracks
  356. }
  357. function transformAnimationData(keyframes, property, defaultValue) {
  358. let keyframe
  359. let empty = true
  360. let i, l
  361. // check, if values of a property are missing in our keyframes
  362. for (i = 0, l = keyframes.length; i < l; i++) {
  363. keyframe = keyframes[i]
  364. if (keyframe.value[property] === undefined) {
  365. keyframe.value[property] = null // mark as missing
  366. } else {
  367. empty = false
  368. }
  369. }
  370. if (empty === true) {
  371. // no values at all, so we set a default value
  372. for (i = 0, l = keyframes.length; i < l; i++) {
  373. keyframe = keyframes[i]
  374. keyframe.value[property] = defaultValue
  375. }
  376. } else {
  377. // filling gaps
  378. createMissingKeyframes(keyframes, property)
  379. }
  380. }
  381. function createMissingKeyframes(keyframes, property) {
  382. let prev, next
  383. for (let i = 0, l = keyframes.length; i < l; i++) {
  384. const keyframe = keyframes[i]
  385. if (keyframe.value[property] === null) {
  386. prev = getPrev(keyframes, i, property)
  387. next = getNext(keyframes, i, property)
  388. if (prev === null) {
  389. keyframe.value[property] = next.value[property]
  390. continue
  391. }
  392. if (next === null) {
  393. keyframe.value[property] = prev.value[property]
  394. continue
  395. }
  396. interpolate(keyframe, prev, next, property)
  397. }
  398. }
  399. }
  400. function getPrev(keyframes, i, property) {
  401. while (i >= 0) {
  402. const keyframe = keyframes[i]
  403. if (keyframe.value[property] !== null) return keyframe
  404. i--
  405. }
  406. return null
  407. }
  408. function getNext(keyframes, i, property) {
  409. while (i < keyframes.length) {
  410. const keyframe = keyframes[i]
  411. if (keyframe.value[property] !== null) return keyframe
  412. i++
  413. }
  414. return null
  415. }
  416. function interpolate(key, prev, next, property) {
  417. if (next.time - prev.time === 0) {
  418. key.value[property] = prev.value[property]
  419. return
  420. }
  421. key.value[property] = ((key.time - prev.time) * (next.value[property] - prev.value[property])) / (next.time - prev.time) + prev.value[property]
  422. }
  423. // animation clips
  424. function parseAnimationClip(xml) {
  425. const data = {
  426. name: xml.getAttribute('id') || 'default',
  427. start: parseFloat(xml.getAttribute('start') || 0),
  428. end: parseFloat(xml.getAttribute('end') || 0),
  429. animations: []
  430. }
  431. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  432. const child = xml.childNodes[i]
  433. if (child.nodeType !== 1) continue
  434. switch (child.nodeName) {
  435. case 'instance_animation':
  436. data.animations.push(parseId(child.getAttribute('url')))
  437. break
  438. }
  439. }
  440. library.clips[xml.getAttribute('id')] = data
  441. }
  442. function buildAnimationClip(data) {
  443. const tracks = []
  444. const name = data.name
  445. const duration = data.end - data.start || -1
  446. const animations = data.animations
  447. for (let i = 0, il = animations.length; i < il; i++) {
  448. const animationTracks = getAnimation(animations[i])
  449. for (let j = 0, jl = animationTracks.length; j < jl; j++) {
  450. tracks.push(animationTracks[j])
  451. }
  452. }
  453. return new AnimationClip(name, duration, tracks)
  454. }
  455. function getAnimationClip(id) {
  456. return getBuild(library.clips[id], buildAnimationClip)
  457. }
  458. // controller
  459. function parseController(xml) {
  460. const data = {}
  461. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  462. const child = xml.childNodes[i]
  463. if (child.nodeType !== 1) continue
  464. switch (child.nodeName) {
  465. case 'skin':
  466. // there is exactly one skin per controller
  467. data.id = parseId(child.getAttribute('source'))
  468. data.skin = parseSkin(child)
  469. break
  470. case 'morph':
  471. data.id = parseId(child.getAttribute('source'))
  472. console.warn('THREE.ColladaLoader: Morph target animation not supported yet.')
  473. break
  474. }
  475. }
  476. library.controllers[xml.getAttribute('id')] = data
  477. }
  478. function parseSkin(xml) {
  479. const data = {
  480. sources: {}
  481. }
  482. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  483. const child = xml.childNodes[i]
  484. if (child.nodeType !== 1) continue
  485. switch (child.nodeName) {
  486. case 'bind_shape_matrix':
  487. data.bindShapeMatrix = parseFloats(child.textContent)
  488. break
  489. case 'source':
  490. const id = child.getAttribute('id')
  491. data.sources[id] = parseSource(child)
  492. break
  493. case 'joints':
  494. data.joints = parseJoints(child)
  495. break
  496. case 'vertex_weights':
  497. data.vertexWeights = parseVertexWeights(child)
  498. break
  499. }
  500. }
  501. return data
  502. }
  503. function parseJoints(xml) {
  504. const data = {
  505. inputs: {}
  506. }
  507. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  508. const child = xml.childNodes[i]
  509. if (child.nodeType !== 1) continue
  510. switch (child.nodeName) {
  511. case 'input':
  512. const semantic = child.getAttribute('semantic')
  513. const id = parseId(child.getAttribute('source'))
  514. data.inputs[semantic] = id
  515. break
  516. }
  517. }
  518. return data
  519. }
  520. function parseVertexWeights(xml) {
  521. const data = {
  522. inputs: {}
  523. }
  524. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  525. const child = xml.childNodes[i]
  526. if (child.nodeType !== 1) continue
  527. switch (child.nodeName) {
  528. case 'input':
  529. const semantic = child.getAttribute('semantic')
  530. const id = parseId(child.getAttribute('source'))
  531. const offset = parseInt(child.getAttribute('offset'))
  532. data.inputs[semantic] = { id: id, offset: offset }
  533. break
  534. case 'vcount':
  535. data.vcount = parseInts(child.textContent)
  536. break
  537. case 'v':
  538. data.v = parseInts(child.textContent)
  539. break
  540. }
  541. }
  542. return data
  543. }
  544. function buildController(data) {
  545. const build = {
  546. id: data.id
  547. }
  548. const geometry = library.geometries[build.id]
  549. if (data.skin !== undefined) {
  550. build.skin = buildSkin(data.skin)
  551. // we enhance the 'sources' property of the corresponding geometry with our skin data
  552. geometry.sources.skinIndices = build.skin.indices
  553. geometry.sources.skinWeights = build.skin.weights
  554. }
  555. return build
  556. }
  557. function buildSkin(data) {
  558. const BONE_LIMIT = 4
  559. const build = {
  560. joints: [], // this must be an array to preserve the joint order
  561. indices: {
  562. array: [],
  563. stride: BONE_LIMIT
  564. },
  565. weights: {
  566. array: [],
  567. stride: BONE_LIMIT
  568. }
  569. }
  570. const sources = data.sources
  571. const vertexWeights = data.vertexWeights
  572. const vcount = vertexWeights.vcount
  573. const v = vertexWeights.v
  574. const jointOffset = vertexWeights.inputs.JOINT.offset
  575. const weightOffset = vertexWeights.inputs.WEIGHT.offset
  576. const jointSource = data.sources[data.joints.inputs.JOINT]
  577. const inverseSource = data.sources[data.joints.inputs.INV_BIND_MATRIX]
  578. const weights = sources[vertexWeights.inputs.WEIGHT.id].array
  579. let stride = 0
  580. let i, j, l
  581. // procces skin data for each vertex
  582. for (i = 0, l = vcount.length; i < l; i++) {
  583. const jointCount = vcount[i] // this is the amount of joints that affect a single vertex
  584. const vertexSkinData = []
  585. for (j = 0; j < jointCount; j++) {
  586. const skinIndex = v[stride + jointOffset]
  587. const weightId = v[stride + weightOffset]
  588. const skinWeight = weights[weightId]
  589. vertexSkinData.push({ index: skinIndex, weight: skinWeight })
  590. stride += 2
  591. }
  592. // we sort the joints in descending order based on the weights.
  593. // this ensures, we only procced the most important joints of the vertex
  594. vertexSkinData.sort(descending)
  595. // now we provide for each vertex a set of four index and weight values.
  596. // the order of the skin data matches the order of vertices
  597. for (j = 0; j < BONE_LIMIT; j++) {
  598. const d = vertexSkinData[j]
  599. if (d !== undefined) {
  600. build.indices.array.push(d.index)
  601. build.weights.array.push(d.weight)
  602. } else {
  603. build.indices.array.push(0)
  604. build.weights.array.push(0)
  605. }
  606. }
  607. }
  608. // setup bind matrix
  609. if (data.bindShapeMatrix) {
  610. build.bindMatrix = new Matrix4().fromArray(data.bindShapeMatrix).transpose()
  611. } else {
  612. build.bindMatrix = new Matrix4().identity()
  613. }
  614. // process bones and inverse bind matrix data
  615. for (i = 0, l = jointSource.array.length; i < l; i++) {
  616. const name = jointSource.array[i]
  617. const boneInverse = new Matrix4().fromArray(inverseSource.array, i * inverseSource.stride).transpose()
  618. build.joints.push({ name: name, boneInverse: boneInverse })
  619. }
  620. return build
  621. // array sort function
  622. function descending(a, b) {
  623. return b.weight - a.weight
  624. }
  625. }
  626. function getController(id) {
  627. return getBuild(library.controllers[id], buildController)
  628. }
  629. // image
  630. function parseImage(xml) {
  631. const data = {
  632. init_from: getElementsByTagName(xml, 'init_from')[0].textContent
  633. }
  634. library.images[xml.getAttribute('id')] = data
  635. }
  636. function buildImage(data) {
  637. if (data.build !== undefined) return data.build
  638. return data.init_from
  639. }
  640. function getImage(id) {
  641. const data = library.images[id]
  642. if (data !== undefined) {
  643. return getBuild(data, buildImage)
  644. }
  645. console.warn("THREE.ColladaLoader: Couldn't find image with ID:", id)
  646. return null
  647. }
  648. // effect
  649. function parseEffect(xml) {
  650. const data = {}
  651. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  652. const child = xml.childNodes[i]
  653. if (child.nodeType !== 1) continue
  654. switch (child.nodeName) {
  655. case 'profile_COMMON':
  656. data.profile = parseEffectProfileCOMMON(child)
  657. break
  658. }
  659. }
  660. library.effects[xml.getAttribute('id')] = data
  661. }
  662. function parseEffectProfileCOMMON(xml) {
  663. const data = {
  664. surfaces: {},
  665. samplers: {}
  666. }
  667. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  668. const child = xml.childNodes[i]
  669. if (child.nodeType !== 1) continue
  670. switch (child.nodeName) {
  671. case 'newparam':
  672. parseEffectNewparam(child, data)
  673. break
  674. case 'technique':
  675. data.technique = parseEffectTechnique(child)
  676. break
  677. case 'extra':
  678. data.extra = parseEffectExtra(child)
  679. break
  680. }
  681. }
  682. return data
  683. }
  684. function parseEffectNewparam(xml, data) {
  685. const sid = xml.getAttribute('sid')
  686. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  687. const child = xml.childNodes[i]
  688. if (child.nodeType !== 1) continue
  689. switch (child.nodeName) {
  690. case 'surface':
  691. data.surfaces[sid] = parseEffectSurface(child)
  692. break
  693. case 'sampler2D':
  694. data.samplers[sid] = parseEffectSampler(child)
  695. break
  696. }
  697. }
  698. }
  699. function parseEffectSurface(xml) {
  700. const data = {}
  701. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  702. const child = xml.childNodes[i]
  703. if (child.nodeType !== 1) continue
  704. switch (child.nodeName) {
  705. case 'init_from':
  706. data.init_from = child.textContent
  707. break
  708. }
  709. }
  710. return data
  711. }
  712. function parseEffectSampler(xml) {
  713. const data = {}
  714. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  715. const child = xml.childNodes[i]
  716. if (child.nodeType !== 1) continue
  717. switch (child.nodeName) {
  718. case 'source':
  719. data.source = child.textContent
  720. break
  721. }
  722. }
  723. return data
  724. }
  725. function parseEffectTechnique(xml) {
  726. const data = {}
  727. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  728. const child = xml.childNodes[i]
  729. if (child.nodeType !== 1) continue
  730. switch (child.nodeName) {
  731. case 'constant':
  732. case 'lambert':
  733. case 'blinn':
  734. case 'phong':
  735. data.type = child.nodeName
  736. data.parameters = parseEffectParameters(child)
  737. break
  738. case 'extra':
  739. data.extra = parseEffectExtra(child)
  740. break
  741. }
  742. }
  743. return data
  744. }
  745. function parseEffectParameters(xml) {
  746. const data = {}
  747. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  748. const child = xml.childNodes[i]
  749. if (child.nodeType !== 1) continue
  750. switch (child.nodeName) {
  751. case 'emission':
  752. case 'diffuse':
  753. case 'specular':
  754. case 'bump':
  755. case 'ambient':
  756. case 'shininess':
  757. case 'transparency':
  758. data[child.nodeName] = parseEffectParameter(child)
  759. break
  760. case 'transparent':
  761. data[child.nodeName] = {
  762. opaque: child.hasAttribute('opaque') ? child.getAttribute('opaque') : 'A_ONE',
  763. data: parseEffectParameter(child)
  764. }
  765. break
  766. }
  767. }
  768. return data
  769. }
  770. function parseEffectParameter(xml) {
  771. const data = {}
  772. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  773. const child = xml.childNodes[i]
  774. if (child.nodeType !== 1) continue
  775. switch (child.nodeName) {
  776. case 'color':
  777. data[child.nodeName] = parseFloats(child.textContent)
  778. break
  779. case 'float':
  780. data[child.nodeName] = parseFloat(child.textContent)
  781. break
  782. case 'texture':
  783. data[child.nodeName] = { id: child.getAttribute('texture'), extra: parseEffectParameterTexture(child) }
  784. break
  785. }
  786. }
  787. return data
  788. }
  789. function parseEffectParameterTexture(xml) {
  790. const data = {
  791. technique: {}
  792. }
  793. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  794. const child = xml.childNodes[i]
  795. if (child.nodeType !== 1) continue
  796. switch (child.nodeName) {
  797. case 'extra':
  798. parseEffectParameterTextureExtra(child, data)
  799. break
  800. }
  801. }
  802. return data
  803. }
  804. function parseEffectParameterTextureExtra(xml, data) {
  805. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  806. const child = xml.childNodes[i]
  807. if (child.nodeType !== 1) continue
  808. switch (child.nodeName) {
  809. case 'technique':
  810. parseEffectParameterTextureExtraTechnique(child, data)
  811. break
  812. }
  813. }
  814. }
  815. function parseEffectParameterTextureExtraTechnique(xml, data) {
  816. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  817. const child = xml.childNodes[i]
  818. if (child.nodeType !== 1) continue
  819. switch (child.nodeName) {
  820. case 'repeatU':
  821. case 'repeatV':
  822. case 'offsetU':
  823. case 'offsetV':
  824. data.technique[child.nodeName] = parseFloat(child.textContent)
  825. break
  826. case 'wrapU':
  827. case 'wrapV':
  828. // some files have values for wrapU/wrapV which become NaN via parseInt
  829. if (child.textContent.toUpperCase() === 'TRUE') {
  830. data.technique[child.nodeName] = 1
  831. } else if (child.textContent.toUpperCase() === 'FALSE') {
  832. data.technique[child.nodeName] = 0
  833. } else {
  834. data.technique[child.nodeName] = parseInt(child.textContent)
  835. }
  836. break
  837. case 'bump':
  838. data[child.nodeName] = parseEffectExtraTechniqueBump(child)
  839. break
  840. }
  841. }
  842. }
  843. function parseEffectExtra(xml) {
  844. const data = {}
  845. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  846. const child = xml.childNodes[i]
  847. if (child.nodeType !== 1) continue
  848. switch (child.nodeName) {
  849. case 'technique':
  850. data.technique = parseEffectExtraTechnique(child)
  851. break
  852. }
  853. }
  854. return data
  855. }
  856. function parseEffectExtraTechnique(xml) {
  857. const data = {}
  858. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  859. const child = xml.childNodes[i]
  860. if (child.nodeType !== 1) continue
  861. switch (child.nodeName) {
  862. case 'double_sided':
  863. data[child.nodeName] = parseInt(child.textContent)
  864. break
  865. case 'bump':
  866. data[child.nodeName] = parseEffectExtraTechniqueBump(child)
  867. break
  868. }
  869. }
  870. return data
  871. }
  872. function parseEffectExtraTechniqueBump(xml) {
  873. const data = {}
  874. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  875. const child = xml.childNodes[i]
  876. if (child.nodeType !== 1) continue
  877. switch (child.nodeName) {
  878. case 'texture':
  879. data[child.nodeName] = { id: child.getAttribute('texture'), texcoord: child.getAttribute('texcoord'), extra: parseEffectParameterTexture(child) }
  880. break
  881. }
  882. }
  883. return data
  884. }
  885. function buildEffect(data) {
  886. return data
  887. }
  888. function getEffect(id) {
  889. return getBuild(library.effects[id], buildEffect)
  890. }
  891. // material
  892. function parseMaterial(xml) {
  893. const data = {
  894. name: xml.getAttribute('name')
  895. }
  896. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  897. const child = xml.childNodes[i]
  898. if (child.nodeType !== 1) continue
  899. switch (child.nodeName) {
  900. case 'instance_effect':
  901. data.url = parseId(child.getAttribute('url'))
  902. break
  903. }
  904. }
  905. library.materials[xml.getAttribute('id')] = data
  906. }
  907. function getTextureLoader(image) {
  908. let loader
  909. let extension = image.slice(((image.lastIndexOf('.') - 1) >>> 0) + 2) // http://www.jstips.co/en/javascript/get-file-extension/
  910. extension = extension.toLowerCase()
  911. switch (extension) {
  912. case 'tga':
  913. loader = tgaLoader
  914. break
  915. default:
  916. loader = textureLoader
  917. }
  918. return loader
  919. }
  920. function buildMaterial(data) {
  921. const effect = getEffect(data.url)
  922. const technique = effect.profile.technique
  923. let material
  924. switch (technique.type) {
  925. case 'phong':
  926. case 'blinn':
  927. material = new MeshPhongMaterial()
  928. break
  929. case 'lambert':
  930. material = new MeshLambertMaterial()
  931. break
  932. default:
  933. material = new MeshBasicMaterial()
  934. break
  935. }
  936. material.name = data.name || ''
  937. function getTexture(textureObject, encoding = null) {
  938. const sampler = effect.profile.samplers[textureObject.id]
  939. let image = null
  940. // get image
  941. if (sampler !== undefined) {
  942. const surface = effect.profile.surfaces[sampler.source]
  943. image = getImage(surface.init_from)
  944. } else {
  945. console.warn('THREE.ColladaLoader: Undefined sampler. Access image directly (see #12530).')
  946. image = getImage(textureObject.id)
  947. }
  948. // create texture if image is avaiable
  949. if (image !== null) {
  950. const loader = getTextureLoader(image)
  951. if (loader !== undefined) {
  952. const texture = loader.load(image)
  953. const extra = textureObject.extra
  954. if (extra !== undefined && extra.technique !== undefined && isEmpty(extra.technique) === false) {
  955. const technique = extra.technique
  956. texture.wrapS = technique.wrapU ? RepeatWrapping : ClampToEdgeWrapping
  957. texture.wrapT = technique.wrapV ? RepeatWrapping : ClampToEdgeWrapping
  958. texture.offset.set(technique.offsetU || 0, technique.offsetV || 0)
  959. texture.repeat.set(technique.repeatU || 1, technique.repeatV || 1)
  960. } else {
  961. texture.wrapS = RepeatWrapping
  962. texture.wrapT = RepeatWrapping
  963. }
  964. if (encoding !== null) {
  965. texture.encoding = encoding
  966. }
  967. return texture
  968. } else {
  969. console.warn('THREE.ColladaLoader: Loader for texture %s not found.', image)
  970. return null
  971. }
  972. } else {
  973. console.warn("THREE.ColladaLoader: Couldn't create texture with ID:", textureObject.id)
  974. return null
  975. }
  976. }
  977. const parameters = technique.parameters
  978. for (const key in parameters) {
  979. const parameter = parameters[key]
  980. switch (key) {
  981. case 'diffuse':
  982. if (parameter.color) material.color.fromArray(parameter.color)
  983. if (parameter.texture) material.map = getTexture(parameter.texture, sRGBEncoding)
  984. break
  985. case 'specular':
  986. if (parameter.color && material.specular) material.specular.fromArray(parameter.color)
  987. if (parameter.texture) material.specularMap = getTexture(parameter.texture)
  988. break
  989. case 'bump':
  990. if (parameter.texture) material.normalMap = getTexture(parameter.texture)
  991. break
  992. case 'ambient':
  993. if (parameter.texture) material.lightMap = getTexture(parameter.texture, sRGBEncoding)
  994. break
  995. case 'shininess':
  996. if (parameter.float && material.shininess) material.shininess = parameter.float
  997. break
  998. case 'emission':
  999. if (parameter.color && material.emissive) material.emissive.fromArray(parameter.color)
  1000. if (parameter.texture) material.emissiveMap = getTexture(parameter.texture, sRGBEncoding)
  1001. break
  1002. }
  1003. }
  1004. material.color.convertSRGBToLinear()
  1005. if (material.specular) material.specular.convertSRGBToLinear()
  1006. if (material.emissive) material.emissive.convertSRGBToLinear()
  1007. //
  1008. let transparent = parameters['transparent']
  1009. let transparency = parameters['transparency']
  1010. // <transparency> does not exist but <transparent>
  1011. if (transparency === undefined && transparent) {
  1012. transparency = {
  1013. float: 1
  1014. }
  1015. }
  1016. // <transparent> does not exist but <transparency>
  1017. if (transparent === undefined && transparency) {
  1018. transparent = {
  1019. opaque: 'A_ONE',
  1020. data: {
  1021. color: [1, 1, 1, 1]
  1022. }
  1023. }
  1024. }
  1025. if (transparent && transparency) {
  1026. // handle case if a texture exists but no color
  1027. if (transparent.data.texture) {
  1028. // we do not set an alpha map (see #13792)
  1029. material.transparent = true
  1030. } else {
  1031. const color = transparent.data.color
  1032. switch (transparent.opaque) {
  1033. case 'A_ONE':
  1034. material.opacity = color[3] * transparency.float
  1035. break
  1036. case 'RGB_ZERO':
  1037. material.opacity = 1 - color[0] * transparency.float
  1038. break
  1039. case 'A_ZERO':
  1040. material.opacity = 1 - color[3] * transparency.float
  1041. break
  1042. case 'RGB_ONE':
  1043. material.opacity = color[0] * transparency.float
  1044. break
  1045. default:
  1046. console.warn('THREE.ColladaLoader: Invalid opaque type "%s" of transparent tag.', transparent.opaque)
  1047. }
  1048. if (material.opacity < 1) material.transparent = true
  1049. }
  1050. }
  1051. //
  1052. if (technique.extra !== undefined && technique.extra.technique !== undefined) {
  1053. const techniques = technique.extra.technique
  1054. for (const k in techniques) {
  1055. const v = techniques[k]
  1056. switch (k) {
  1057. case 'double_sided':
  1058. material.side = v === 1 ? DoubleSide : FrontSide
  1059. break
  1060. case 'bump':
  1061. material.normalMap = getTexture(v.texture)
  1062. material.normalScale = new Vector2(1, 1)
  1063. break
  1064. }
  1065. }
  1066. }
  1067. return material
  1068. }
  1069. function getMaterial(id) {
  1070. return getBuild(library.materials[id], buildMaterial)
  1071. }
  1072. // camera
  1073. function parseCamera(xml) {
  1074. const data = {
  1075. name: xml.getAttribute('name')
  1076. }
  1077. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  1078. const child = xml.childNodes[i]
  1079. if (child.nodeType !== 1) continue
  1080. switch (child.nodeName) {
  1081. case 'optics':
  1082. data.optics = parseCameraOptics(child)
  1083. break
  1084. }
  1085. }
  1086. library.cameras[xml.getAttribute('id')] = data
  1087. }
  1088. function parseCameraOptics(xml) {
  1089. for (let i = 0; i < xml.childNodes.length; i++) {
  1090. const child = xml.childNodes[i]
  1091. switch (child.nodeName) {
  1092. case 'technique_common':
  1093. return parseCameraTechnique(child)
  1094. }
  1095. }
  1096. return {}
  1097. }
  1098. function parseCameraTechnique(xml) {
  1099. const data = {}
  1100. for (let i = 0; i < xml.childNodes.length; i++) {
  1101. const child = xml.childNodes[i]
  1102. switch (child.nodeName) {
  1103. case 'perspective':
  1104. case 'orthographic':
  1105. data.technique = child.nodeName
  1106. data.parameters = parseCameraParameters(child)
  1107. break
  1108. }
  1109. }
  1110. return data
  1111. }
  1112. function parseCameraParameters(xml) {
  1113. const data = {}
  1114. for (let i = 0; i < xml.childNodes.length; i++) {
  1115. const child = xml.childNodes[i]
  1116. switch (child.nodeName) {
  1117. case 'xfov':
  1118. case 'yfov':
  1119. case 'xmag':
  1120. case 'ymag':
  1121. case 'znear':
  1122. case 'zfar':
  1123. case 'aspect_ratio':
  1124. data[child.nodeName] = parseFloat(child.textContent)
  1125. break
  1126. }
  1127. }
  1128. return data
  1129. }
  1130. function buildCamera(data) {
  1131. let camera
  1132. switch (data.optics.technique) {
  1133. case 'perspective':
  1134. camera = new PerspectiveCamera(data.optics.parameters.yfov, data.optics.parameters.aspect_ratio, data.optics.parameters.znear, data.optics.parameters.zfar)
  1135. break
  1136. case 'orthographic':
  1137. let ymag = data.optics.parameters.ymag
  1138. let xmag = data.optics.parameters.xmag
  1139. const aspectRatio = data.optics.parameters.aspect_ratio
  1140. xmag = xmag === undefined ? ymag * aspectRatio : xmag
  1141. ymag = ymag === undefined ? xmag / aspectRatio : ymag
  1142. xmag *= 0.5
  1143. ymag *= 0.5
  1144. camera = new OrthographicCamera(
  1145. -xmag,
  1146. xmag,
  1147. ymag,
  1148. -ymag, // left, right, top, bottom
  1149. data.optics.parameters.znear,
  1150. data.optics.parameters.zfar
  1151. )
  1152. break
  1153. default:
  1154. camera = new PerspectiveCamera()
  1155. break
  1156. }
  1157. camera.name = data.name || ''
  1158. return camera
  1159. }
  1160. function getCamera(id) {
  1161. const data = library.cameras[id]
  1162. if (data !== undefined) {
  1163. return getBuild(data, buildCamera)
  1164. }
  1165. console.warn("THREE.ColladaLoader: Couldn't find camera with ID:", id)
  1166. return null
  1167. }
  1168. // light
  1169. function parseLight(xml) {
  1170. let data = {}
  1171. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  1172. const child = xml.childNodes[i]
  1173. if (child.nodeType !== 1) continue
  1174. switch (child.nodeName) {
  1175. case 'technique_common':
  1176. data = parseLightTechnique(child)
  1177. break
  1178. }
  1179. }
  1180. library.lights[xml.getAttribute('id')] = data
  1181. }
  1182. function parseLightTechnique(xml) {
  1183. const data = {}
  1184. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  1185. const child = xml.childNodes[i]
  1186. if (child.nodeType !== 1) continue
  1187. switch (child.nodeName) {
  1188. case 'directional':
  1189. case 'point':
  1190. case 'spot':
  1191. case 'ambient':
  1192. data.technique = child.nodeName
  1193. data.parameters = parseLightParameters(child)
  1194. }
  1195. }
  1196. return data
  1197. }
  1198. function parseLightParameters(xml) {
  1199. const data = {}
  1200. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  1201. const child = xml.childNodes[i]
  1202. if (child.nodeType !== 1) continue
  1203. switch (child.nodeName) {
  1204. case 'color':
  1205. const array = parseFloats(child.textContent)
  1206. data.color = new Color().fromArray(array).convertSRGBToLinear()
  1207. break
  1208. case 'falloff_angle':
  1209. data.falloffAngle = parseFloat(child.textContent)
  1210. break
  1211. case 'quadratic_attenuation':
  1212. const f = parseFloat(child.textContent)
  1213. data.distance = f ? Math.sqrt(1 / f) : 0
  1214. break
  1215. }
  1216. }
  1217. return data
  1218. }
  1219. function buildLight(data) {
  1220. let light
  1221. switch (data.technique) {
  1222. case 'directional':
  1223. light = new DirectionalLight()
  1224. break
  1225. case 'point':
  1226. light = new PointLight()
  1227. break
  1228. case 'spot':
  1229. light = new SpotLight()
  1230. break
  1231. case 'ambient':
  1232. light = new AmbientLight()
  1233. break
  1234. }
  1235. if (data.parameters.color) light.color.copy(data.parameters.color)
  1236. if (data.parameters.distance) light.distance = data.parameters.distance
  1237. return light
  1238. }
  1239. function getLight(id) {
  1240. const data = library.lights[id]
  1241. if (data !== undefined) {
  1242. return getBuild(data, buildLight)
  1243. }
  1244. console.warn("THREE.ColladaLoader: Couldn't find light with ID:", id)
  1245. return null
  1246. }
  1247. // geometry
  1248. function parseGeometry(xml) {
  1249. const data = {
  1250. name: xml.getAttribute('name'),
  1251. sources: {},
  1252. vertices: {},
  1253. primitives: []
  1254. }
  1255. const mesh = getElementsByTagName(xml, 'mesh')[0]
  1256. // the following tags inside geometry are not supported yet (see https://github.com/mrdoob/three.js/pull/12606): convex_mesh, spline, brep
  1257. if (mesh === undefined) return
  1258. for (let i = 0; i < mesh.childNodes.length; i++) {
  1259. const child = mesh.childNodes[i]
  1260. if (child.nodeType !== 1) continue
  1261. const id = child.getAttribute('id')
  1262. switch (child.nodeName) {
  1263. case 'source':
  1264. data.sources[id] = parseSource(child)
  1265. break
  1266. case 'vertices':
  1267. // data.sources[ id ] = data.sources[ parseId( getElementsByTagName( child, 'input' )[ 0 ].getAttribute( 'source' ) ) ];
  1268. data.vertices = parseGeometryVertices(child)
  1269. break
  1270. case 'polygons':
  1271. console.warn('THREE.ColladaLoader: Unsupported primitive type: ', child.nodeName)
  1272. break
  1273. case 'lines':
  1274. case 'linestrips':
  1275. case 'polylist':
  1276. case 'triangles':
  1277. data.primitives.push(parseGeometryPrimitive(child))
  1278. break
  1279. default:
  1280. console.log(child)
  1281. }
  1282. }
  1283. library.geometries[xml.getAttribute('id')] = data
  1284. }
  1285. function parseSource(xml) {
  1286. const data = {
  1287. array: [],
  1288. stride: 3
  1289. }
  1290. for (let i = 0; i < xml.childNodes.length; i++) {
  1291. const child = xml.childNodes[i]
  1292. if (child.nodeType !== 1) continue
  1293. switch (child.nodeName) {
  1294. case 'float_array':
  1295. data.array = parseFloats(child.textContent)
  1296. break
  1297. case 'Name_array':
  1298. data.array = parseStrings(child.textContent)
  1299. break
  1300. case 'technique_common':
  1301. const accessor = getElementsByTagName(child, 'accessor')[0]
  1302. if (accessor !== undefined) {
  1303. data.stride = parseInt(accessor.getAttribute('stride'))
  1304. }
  1305. break
  1306. }
  1307. }
  1308. return data
  1309. }
  1310. function parseGeometryVertices(xml) {
  1311. const data = {}
  1312. for (let i = 0; i < xml.childNodes.length; i++) {
  1313. const child = xml.childNodes[i]
  1314. if (child.nodeType !== 1) continue
  1315. data[child.getAttribute('semantic')] = parseId(child.getAttribute('source'))
  1316. }
  1317. return data
  1318. }
  1319. function parseGeometryPrimitive(xml) {
  1320. const primitive = {
  1321. type: xml.nodeName,
  1322. material: xml.getAttribute('material'),
  1323. count: parseInt(xml.getAttribute('count')),
  1324. inputs: {},
  1325. stride: 0,
  1326. hasUV: false
  1327. }
  1328. for (let i = 0, l = xml.childNodes.length; i < l; i++) {
  1329. const child = xml.childNodes[i]
  1330. if (child.nodeType !== 1) continue
  1331. switch (child.nodeName) {
  1332. case 'input':
  1333. const id = parseId(child.getAttribute('source'))
  1334. const semantic = child.getAttribute('semantic')
  1335. const offset = parseInt(child.getAttribute('offset'))
  1336. const set = parseInt(child.getAttribute('set'))
  1337. const inputname = set > 0 ? semantic + set : semantic
  1338. primitive.inputs[inputname] = { id: id, offset: offset }
  1339. primitive.stride = Math.max(primitive.stride, offset + 1)
  1340. if (semantic === 'TEXCOORD') primitive.hasUV = true
  1341. break
  1342. case 'vcount':
  1343. primitive.vcount = parseInts(child.textContent)
  1344. break
  1345. case 'p':
  1346. primitive.p = parseInts(child.textContent)
  1347. break
  1348. }
  1349. }
  1350. return primitive
  1351. }
  1352. function groupPrimitives(primitives) {
  1353. const build = {}
  1354. for (let i = 0; i < primitives.length; i++) {
  1355. const primitive = primitives[i]
  1356. if (build[primitive.type] === undefined) build[primitive.type] = []
  1357. build[primitive.type].push(primitive)
  1358. }
  1359. return build
  1360. }
  1361. function checkUVCoordinates(primitives) {
  1362. let count = 0
  1363. for (let i = 0, l = primitives.length; i < l; i++) {
  1364. const primitive = primitives[i]
  1365. if (primitive.hasUV === true) {
  1366. count++
  1367. }
  1368. }
  1369. if (count > 0 && count < primitives.length) {
  1370. primitives.uvsNeedsFix = true
  1371. }
  1372. }
  1373. function buildGeometry(data) {
  1374. const build = {}
  1375. const sources = data.sources
  1376. const vertices = data.vertices
  1377. const primitives = data.primitives
  1378. if (primitives.length === 0) return {}
  1379. // our goal is to create one buffer geometry for a single type of primitives
  1380. // first, we group all primitives by their type
  1381. const groupedPrimitives = groupPrimitives(primitives)
  1382. for (const type in groupedPrimitives) {
  1383. const primitiveType = groupedPrimitives[type]
  1384. // second, ensure consistent uv coordinates for each type of primitives (polylist,triangles or lines)
  1385. checkUVCoordinates(primitiveType)
  1386. // third, create a buffer geometry for each type of primitives
  1387. build[type] = buildGeometryType(primitiveType, sources, vertices)
  1388. }
  1389. return build
  1390. }
  1391. function buildGeometryType(primitives, sources, vertices) {
  1392. const build = {}
  1393. const position = { array: [], stride: 0 }
  1394. const normal = { array: [], stride: 0 }
  1395. const uv = { array: [], stride: 0 }
  1396. const uv2 = { array: [], stride: 0 }
  1397. const color = { array: [], stride: 0 }
  1398. const skinIndex = { array: [], stride: 4 }
  1399. const skinWeight = { array: [], stride: 4 }
  1400. const geometry = new BufferGeometry()
  1401. const materialKeys = []
  1402. let start = 0
  1403. for (let p = 0; p < primitives.length; p++) {
  1404. const primitive = primitives[p]
  1405. const inputs = primitive.inputs
  1406. // groups
  1407. let count = 0
  1408. switch (primitive.type) {
  1409. case 'lines':
  1410. case 'linestrips':
  1411. count = primitive.count * 2
  1412. break
  1413. case 'triangles':
  1414. count = primitive.count * 3
  1415. break
  1416. case 'polylist':
  1417. for (let g = 0; g < primitive.count; g++) {
  1418. const vc = primitive.vcount[g]
  1419. switch (vc) {
  1420. case 3:
  1421. count += 3 // single triangle
  1422. break
  1423. case 4:
  1424. count += 6 // quad, subdivided into two triangles
  1425. break
  1426. default:
  1427. count += (vc - 2) * 3 // polylist with more than four vertices
  1428. break
  1429. }
  1430. }
  1431. break
  1432. default:
  1433. console.warn('THREE.ColladaLoader: Unknow primitive type:', primitive.type)
  1434. }
  1435. geometry.addGroup(start, count, p)
  1436. start += count
  1437. // material
  1438. if (primitive.material) {
  1439. materialKeys.push(primitive.material)
  1440. }
  1441. // geometry data
  1442. for (const name in inputs) {
  1443. const input = inputs[name]
  1444. switch (name) {
  1445. case 'VERTEX':
  1446. for (const key in vertices) {
  1447. const id = vertices[key]
  1448. switch (key) {
  1449. case 'POSITION':
  1450. const prevLength = position.array.length
  1451. buildGeometryData(primitive, sources[id], input.offset, position.array)
  1452. position.stride = sources[id].stride
  1453. if (sources.skinWeights && sources.skinIndices) {
  1454. buildGeometryData(primitive, sources.skinIndices, input.offset, skinIndex.array)
  1455. buildGeometryData(primitive, sources.skinWeights, input.offset, skinWeight.array)
  1456. }
  1457. // see #3803
  1458. if (primitive.hasUV === false && primitives.uvsNeedsFix === true) {
  1459. const count = (position.array.length - prevLength) / position.stride
  1460. for (let i = 0; i < count; i++) {
  1461. // fill missing uv coordinates
  1462. uv.array.push(0, 0)
  1463. }
  1464. }
  1465. break
  1466. case 'NORMAL':
  1467. buildGeometryData(primitive, sources[id], input.offset, normal.array)
  1468. normal.stride = sources[id].stride
  1469. break
  1470. case 'COLOR':
  1471. buildGeometryData(primitive, sources[id], input.offset, color.array)
  1472. color.stride = sources[id].stride
  1473. break
  1474. case 'TEXCOORD':
  1475. buildGeometryData(primitive, sources[id], input.offset, uv.array)
  1476. uv.stride = sources[id].stride
  1477. break
  1478. case 'TEXCOORD1':
  1479. buildGeometryData(primitive, sources[id], input.offset, uv2.array)
  1480. uv.stride = sources[id].stride
  1481. break
  1482. default:
  1483. console.warn('THREE.ColladaLoader: Semantic "%s" not handled in geometry build process.', key)
  1484. }
  1485. }
  1486. break
  1487. case 'NORMAL':
  1488. buildGeometryData(primitive, sources[input.id], input.offset, normal.array)
  1489. normal.stride = sources[input.id].stride
  1490. break
  1491. case 'COLOR':
  1492. buildGeometryData(primitive, sources[input.id], input.offset, color.array, true)
  1493. color.stride = sources[input.id].stride
  1494. break
  1495. case 'TEXCOORD':
  1496. buildGeometryData(primitive, sources[input.id], input.offset, uv.array)
  1497. uv.stride = sources[input.id].stride
  1498. break
  1499. case 'TEXCOORD1':
  1500. buildGeometryData(primitive, sources[input.id], input.offset, uv2.array)
  1501. uv2.stride = sources[input.id].stride
  1502. break
  1503. }
  1504. }
  1505. }
  1506. // build geometry
  1507. if (position.array.length > 0) geometry.setAttribute('position', new Float32BufferAttribute(position.array, position.stride))
  1508. if (normal.array.length > 0) geometry.setAttribute('normal', new Float32BufferAttribute(normal.array, normal.stride))
  1509. if (color.array.length > 0) geometry.setAttribute('color', new Float32BufferAttribute(color.array, color.stride))
  1510. if (uv.array.length > 0) geometry.setAttribute('uv', new Float32BufferAttribute(uv.array, uv.stride))
  1511. if (uv2.array.length > 0) geometry.setAttribute('uv2', new Float32BufferAttribute(uv2.array, uv2.stride))
  1512. if (skinIndex.array.length > 0) geometry.setAttribute('skinIndex', new Float32BufferAttribute(skinIndex.array, skinIndex.stride))
  1513. if (skinWeight.array.length > 0) geometry.setAttribute('skinWeight', new Float32BufferAttribute(skinWeight.array, skinWeight.stride))
  1514. build.data = geometry
  1515. build.type = primitives[0].type
  1516. build.materialKeys = materialKeys
  1517. return build
  1518. }
  1519. function buildGeometryData(primitive, source, offset, array, isColor = false) {
  1520. const indices = primitive.p
  1521. const stride = primitive.stride
  1522. const vcount = primitive.vcount
  1523. function pushVector(i) {
  1524. let index = indices[i + offset] * sourceStride
  1525. const length = index + sourceStride
  1526. for (; index < length; index++) {
  1527. array.push(sourceArray[index])
  1528. }
  1529. if (isColor) {
  1530. // convert the vertex colors from srgb to linear if present
  1531. const startIndex = array.length - sourceStride - 1
  1532. tempColor.setRGB(array[startIndex + 0], array[startIndex + 1], array[startIndex + 2]).convertSRGBToLinear()
  1533. array[startIndex + 0] = tempColor.r
  1534. array[startIndex + 1] = tempColor.g
  1535. array[startIndex + 2] = tempColor.b
  1536. }
  1537. }
  1538. const sourceArray = source.array
  1539. const sourceStride = source.stride
  1540. if (primitive.vcount !== undefined) {
  1541. let index = 0
  1542. for (let i = 0, l = vcount.length; i < l; i++) {
  1543. const count = vcount[i]
  1544. if (count === 4) {
  1545. const a = index + stride * 0
  1546. const b = index + stride * 1
  1547. const c = index + stride * 2
  1548. const d = index + stride * 3
  1549. pushVector(a)
  1550. pushVector(b)
  1551. pushVector(d)
  1552. pushVector(b)
  1553. pushVector(c)
  1554. pushVector(d)
  1555. } else if (count === 3) {
  1556. const a = index + stride * 0
  1557. const b = index + stride * 1
  1558. const c = index + stride * 2
  1559. pushVector(a)
  1560. pushVector(b)
  1561. pushVector(c)
  1562. } else if (count > 4) {
  1563. for (let k = 1, kl = count - 2; k <= kl; k++) {
  1564. const a = index + stride * 0
  1565. const b = index + stride * k
  1566. const c = index + stride * (k + 1)
  1567. pushVector(a)
  1568. pushVector(b)
  1569. pushVector(c)
  1570. }
  1571. }
  1572. index += stride * count
  1573. }
  1574. } else {
  1575. for (let i = 0, l = indices.length; i < l; i += stride) {
  1576. pushVector(i)
  1577. }
  1578. }
  1579. }
  1580. function getGeometry(id) {
  1581. return getBuild(library.geometries[id], buildGeometry)
  1582. }
  1583. // kinematics
  1584. function parseKinematicsModel(xml) {
  1585. const data = {
  1586. name: xml.getAttribute('name') || '',
  1587. joints: {},
  1588. links: []
  1589. }
  1590. for (let i = 0; i < xml.childNodes.length; i++) {
  1591. const child = xml.childNodes[i]
  1592. if (child.nodeType !== 1) continue
  1593. switch (child.nodeName) {
  1594. case 'technique_common':
  1595. parseKinematicsTechniqueCommon(child, data)
  1596. break
  1597. }
  1598. }
  1599. library.kinematicsModels[xml.getAttribute('id')] = data
  1600. }
  1601. function buildKinematicsModel(data) {
  1602. if (data.build !== undefined) return data.build
  1603. return data
  1604. }
  1605. function getKinematicsModel(id) {
  1606. return getBuild(library.kinematicsModels[id], buildKinematicsModel)
  1607. }
  1608. function parseKinematicsTechniqueCommon(xml, data) {
  1609. for (let i = 0; i < xml.childNodes.length; i++) {
  1610. const child = xml.childNodes[i]
  1611. if (child.nodeType !== 1) continue
  1612. switch (child.nodeName) {
  1613. case 'joint':
  1614. data.joints[child.getAttribute('sid')] = parseKinematicsJoint(child)
  1615. break
  1616. case 'link':
  1617. data.links.push(parseKinematicsLink(child))
  1618. break
  1619. }
  1620. }
  1621. }
  1622. function parseKinematicsJoint(xml) {
  1623. let data
  1624. for (let i = 0; i < xml.childNodes.length; i++) {
  1625. const child = xml.childNodes[i]
  1626. if (child.nodeType !== 1) continue
  1627. switch (child.nodeName) {
  1628. case 'prismatic':
  1629. case 'revolute':
  1630. data = parseKinematicsJointParameter(child)
  1631. break
  1632. }
  1633. }
  1634. return data
  1635. }
  1636. function parseKinematicsJointParameter(xml) {
  1637. const data = {
  1638. sid: xml.getAttribute('sid'),
  1639. name: xml.getAttribute('name') || '',
  1640. axis: new Vector3(),
  1641. limits: {
  1642. min: 0,
  1643. max: 0
  1644. },
  1645. type: xml.nodeName,
  1646. static: false,
  1647. zeroPosition: 0,
  1648. middlePosition: 0
  1649. }
  1650. for (let i = 0; i < xml.childNodes.length; i++) {
  1651. const child = xml.childNodes[i]
  1652. if (child.nodeType !== 1) continue
  1653. switch (child.nodeName) {
  1654. case 'axis':
  1655. const array = parseFloats(child.textContent)
  1656. data.axis.fromArray(array)
  1657. break
  1658. case 'limits':
  1659. const max = child.getElementsByTagName('max')[0]
  1660. const min = child.getElementsByTagName('min')[0]
  1661. data.limits.max = parseFloat(max.textContent)
  1662. data.limits.min = parseFloat(min.textContent)
  1663. break
  1664. }
  1665. }
  1666. // if min is equal to or greater than max, consider the joint static
  1667. if (data.limits.min >= data.limits.max) {
  1668. data.static = true
  1669. }
  1670. // calculate middle position
  1671. data.middlePosition = (data.limits.min + data.limits.max) / 2.0
  1672. return data
  1673. }
  1674. function parseKinematicsLink(xml) {
  1675. const data = {
  1676. sid: xml.getAttribute('sid'),
  1677. name: xml.getAttribute('name') || '',
  1678. attachments: [],
  1679. transforms: []
  1680. }
  1681. for (let i = 0; i < xml.childNodes.length; i++) {
  1682. const child = xml.childNodes[i]
  1683. if (child.nodeType !== 1) continue
  1684. switch (child.nodeName) {
  1685. case 'attachment_full':
  1686. data.attachments.push(parseKinematicsAttachment(child))
  1687. break
  1688. case 'matrix':
  1689. case 'translate':
  1690. case 'rotate':
  1691. data.transforms.push(parseKinematicsTransform(child))
  1692. break
  1693. }
  1694. }
  1695. return data
  1696. }
  1697. function parseKinematicsAttachment(xml) {
  1698. const data = {
  1699. joint: xml
  1700. .getAttribute('joint')
  1701. .split('/')
  1702. .pop(),
  1703. transforms: [],
  1704. links: []
  1705. }
  1706. for (let i = 0; i < xml.childNodes.length; i++) {
  1707. const child = xml.childNodes[i]
  1708. if (child.nodeType !== 1) continue
  1709. switch (child.nodeName) {
  1710. case 'link':
  1711. data.links.push(parseKinematicsLink(child))
  1712. break
  1713. case 'matrix':
  1714. case 'translate':
  1715. case 'rotate':
  1716. data.transforms.push(parseKinematicsTransform(child))
  1717. break
  1718. }
  1719. }
  1720. return data
  1721. }
  1722. function parseKinematicsTransform(xml) {
  1723. const data = {
  1724. type: xml.nodeName
  1725. }
  1726. const array = parseFloats(xml.textContent)
  1727. switch (data.type) {
  1728. case 'matrix':
  1729. data.obj = new Matrix4()
  1730. data.obj.fromArray(array).transpose()
  1731. break
  1732. case 'translate':
  1733. data.obj = new Vector3()
  1734. data.obj.fromArray(array)
  1735. break
  1736. case 'rotate':
  1737. data.obj = new Vector3()
  1738. data.obj.fromArray(array)
  1739. data.angle = MathUtils.degToRad(array[3])
  1740. break
  1741. }
  1742. return data
  1743. }
  1744. // physics
  1745. function parsePhysicsModel(xml) {
  1746. const data = {
  1747. name: xml.getAttribute('name') || '',
  1748. rigidBodies: {}
  1749. }
  1750. for (let i = 0; i < xml.childNodes.length; i++) {
  1751. const child = xml.childNodes[i]
  1752. if (child.nodeType !== 1) continue
  1753. switch (child.nodeName) {
  1754. case 'rigid_body':
  1755. data.rigidBodies[child.getAttribute('name')] = {}
  1756. parsePhysicsRigidBody(child, data.rigidBodies[child.getAttribute('name')])
  1757. break
  1758. }
  1759. }
  1760. library.physicsModels[xml.getAttribute('id')] = data
  1761. }
  1762. function parsePhysicsRigidBody(xml, data) {
  1763. for (let i = 0; i < xml.childNodes.length; i++) {
  1764. const child = xml.childNodes[i]
  1765. if (child.nodeType !== 1) continue
  1766. switch (child.nodeName) {
  1767. case 'technique_common':
  1768. parsePhysicsTechniqueCommon(child, data)
  1769. break
  1770. }
  1771. }
  1772. }
  1773. function parsePhysicsTechniqueCommon(xml, data) {
  1774. for (let i = 0; i < xml.childNodes.length; i++) {
  1775. const child = xml.childNodes[i]
  1776. if (child.nodeType !== 1) continue
  1777. switch (child.nodeName) {
  1778. case 'inertia':
  1779. data.inertia = parseFloats(child.textContent)
  1780. break
  1781. case 'mass':
  1782. data.mass = parseFloats(child.textContent)[0]
  1783. break
  1784. }
  1785. }
  1786. }
  1787. // scene
  1788. function parseKinematicsScene(xml) {
  1789. const data = {
  1790. bindJointAxis: []
  1791. }
  1792. for (let i = 0; i < xml.childNodes.length; i++) {
  1793. const child = xml.childNodes[i]
  1794. if (child.nodeType !== 1) continue
  1795. switch (child.nodeName) {
  1796. case 'bind_joint_axis':
  1797. data.bindJointAxis.push(parseKinematicsBindJointAxis(child))
  1798. break
  1799. }
  1800. }
  1801. library.kinematicsScenes[parseId(xml.getAttribute('url'))] = data
  1802. }
  1803. function parseKinematicsBindJointAxis(xml) {
  1804. const data = {
  1805. target: xml
  1806. .getAttribute('target')
  1807. .split('/')
  1808. .pop()
  1809. }
  1810. for (let i = 0; i < xml.childNodes.length; i++) {
  1811. const child = xml.childNodes[i]
  1812. if (child.nodeType !== 1) continue
  1813. switch (child.nodeName) {
  1814. case 'axis':
  1815. const param = child.getElementsByTagName('param')[0]
  1816. data.axis = param.textContent
  1817. const tmpJointIndex = data.axis
  1818. .split('inst_')
  1819. .pop()
  1820. .split('axis')[0]
  1821. data.jointIndex = tmpJointIndex.substring(0, tmpJointIndex.length - 1)
  1822. break
  1823. }
  1824. }
  1825. return data
  1826. }
  1827. function buildKinematicsScene(data) {
  1828. if (data.build !== undefined) return data.build
  1829. return data
  1830. }
  1831. function getKinematicsScene(id) {
  1832. return getBuild(library.kinematicsScenes[id], buildKinematicsScene)
  1833. }
  1834. function setupKinematics() {
  1835. const kinematicsModelId = Object.keys(library.kinematicsModels)[0]
  1836. const kinematicsSceneId = Object.keys(library.kinematicsScenes)[0]
  1837. const visualSceneId = Object.keys(library.visualScenes)[0]
  1838. if (kinematicsModelId === undefined || kinematicsSceneId === undefined) return
  1839. const kinematicsModel = getKinematicsModel(kinematicsModelId)
  1840. const kinematicsScene = getKinematicsScene(kinematicsSceneId)
  1841. const visualScene = getVisualScene(visualSceneId)
  1842. const bindJointAxis = kinematicsScene.bindJointAxis
  1843. const jointMap = {}
  1844. for (let i = 0, l = bindJointAxis.length; i < l; i++) {
  1845. const axis = bindJointAxis[i]
  1846. // the result of the following query is an element of type 'translate', 'rotate','scale' or 'matrix'
  1847. const targetElement = collada.querySelector('[sid="' + axis.target + '"]')
  1848. if (targetElement) {
  1849. // get the parent of the transform element
  1850. const parentVisualElement = targetElement.parentElement
  1851. // connect the joint of the kinematics model with the element in the visual scene
  1852. connect(axis.jointIndex, parentVisualElement)
  1853. }
  1854. }
  1855. function connect(jointIndex, visualElement) {
  1856. const visualElementName = visualElement.getAttribute('name')
  1857. const joint = kinematicsModel.joints[jointIndex]
  1858. visualScene.traverse(function(object) {
  1859. if (object.name === visualElementName) {
  1860. jointMap[jointIndex] = {
  1861. object: object,
  1862. transforms: buildTransformList(visualElement),
  1863. joint: joint,
  1864. position: joint.zeroPosition
  1865. }
  1866. }
  1867. })
  1868. }
  1869. const m0 = new Matrix4()
  1870. kinematics = {
  1871. joints: kinematicsModel && kinematicsModel.joints,
  1872. getJointValue: function(jointIndex) {
  1873. const jointData = jointMap[jointIndex]
  1874. if (jointData) {
  1875. return jointData.position
  1876. } else {
  1877. console.warn('THREE.ColladaLoader: Joint ' + jointIndex + " doesn't exist.")
  1878. }
  1879. },
  1880. setJointValue: function(jointIndex, value) {
  1881. const jointData = jointMap[jointIndex]
  1882. if (jointData) {
  1883. const joint = jointData.joint
  1884. if (value > joint.limits.max || value < joint.limits.min) {
  1885. console.warn('THREE.ColladaLoader: Joint ' + jointIndex + ' value ' + value + ' outside of limits (min: ' + joint.limits.min + ', max: ' + joint.limits.max + ').')
  1886. } else if (joint.static) {
  1887. console.warn('THREE.ColladaLoader: Joint ' + jointIndex + ' is static.')
  1888. } else {
  1889. const object = jointData.object
  1890. const axis = joint.axis
  1891. const transforms = jointData.transforms
  1892. matrix.identity()
  1893. // each update, we have to apply all transforms in the correct order
  1894. for (let i = 0; i < transforms.length; i++) {
  1895. const transform = transforms[i]
  1896. // if there is a connection of the transform node with a joint, apply the joint value
  1897. if (transform.sid && transform.sid.indexOf(jointIndex) !== -1) {
  1898. switch (joint.type) {
  1899. case 'revolute':
  1900. matrix.multiply(m0.makeRotationAxis(axis, MathUtils.degToRad(value)))
  1901. break
  1902. case 'prismatic':
  1903. matrix.multiply(m0.makeTranslation(axis.x * value, axis.y * value, axis.z * value))
  1904. break
  1905. default:
  1906. console.warn('THREE.ColladaLoader: Unknown joint type: ' + joint.type)
  1907. break
  1908. }
  1909. } else {
  1910. switch (transform.type) {
  1911. case 'matrix':
  1912. matrix.multiply(transform.obj)
  1913. break
  1914. case 'translate':
  1915. matrix.multiply(m0.makeTranslation(transform.obj.x, transform.obj.y, transform.obj.z))
  1916. break
  1917. case 'scale':
  1918. matrix.scale(transform.obj)
  1919. break
  1920. case 'rotate':
  1921. matrix.multiply(m0.makeRotationAxis(transform.obj, transform.angle))
  1922. break
  1923. }
  1924. }
  1925. }
  1926. object.matrix.copy(matrix)
  1927. object.matrix.decompose(object.position, object.quaternion, object.scale)
  1928. jointMap[jointIndex].position = value
  1929. }
  1930. } else {
  1931. console.log('THREE.ColladaLoader: ' + jointIndex + ' does not exist.')
  1932. }
  1933. }
  1934. }
  1935. }
  1936. function buildTransformList(node) {
  1937. const transforms = []
  1938. const xml = collada.querySelector('[id="' + node.id + '"]')
  1939. for (let i = 0; i < xml.childNodes.length; i++) {
  1940. const child = xml.childNodes[i]
  1941. if (child.nodeType !== 1) continue
  1942. let array, vector
  1943. switch (child.nodeName) {
  1944. case 'matrix':
  1945. array = parseFloats(child.textContent)
  1946. const matrix = new Matrix4().fromArray(array).transpose()
  1947. transforms.push({
  1948. sid: child.getAttribute('sid'),
  1949. type: child.nodeName,
  1950. obj: matrix
  1951. })
  1952. break
  1953. case 'translate':
  1954. case 'scale':
  1955. array = parseFloats(child.textContent)
  1956. vector = new Vector3().fromArray(array)
  1957. transforms.push({
  1958. sid: child.getAttribute('sid'),
  1959. type: child.nodeName,
  1960. obj: vector
  1961. })
  1962. break
  1963. case 'rotate':
  1964. array = parseFloats(child.textContent)
  1965. vector = new Vector3().fromArray(array)
  1966. const angle = MathUtils.degToRad(array[3])
  1967. transforms.push({
  1968. sid: child.getAttribute('sid'),
  1969. type: child.nodeName,
  1970. obj: vector,
  1971. angle: angle
  1972. })
  1973. break
  1974. }
  1975. }
  1976. return transforms
  1977. }
  1978. // nodes
  1979. function prepareNodes(xml) {
  1980. const elements = xml.getElementsByTagName('node')
  1981. // ensure all node elements have id attributes
  1982. for (let i = 0; i < elements.length; i++) {
  1983. const element = elements[i]
  1984. if (element.hasAttribute('id') === false) {
  1985. element.setAttribute('id', generateId())
  1986. }
  1987. }
  1988. }
  1989. const matrix = new Matrix4()
  1990. const vector = new Vector3()
  1991. function parseNode(xml) {
  1992. const data = {
  1993. name: xml.getAttribute('name') || '',
  1994. type: xml.getAttribute('type'),
  1995. id: xml.getAttribute('id'),
  1996. sid: xml.getAttribute('sid'),
  1997. matrix: new Matrix4(),
  1998. nodes: [],
  1999. instanceCameras: [],
  2000. instanceControllers: [],
  2001. instanceLights: [],
  2002. instanceGeometries: [],
  2003. instanceNodes: [],
  2004. transforms: {}
  2005. }
  2006. for (let i = 0; i < xml.childNodes.length; i++) {
  2007. const child = xml.childNodes[i]
  2008. if (child.nodeType !== 1) continue
  2009. let array
  2010. switch (child.nodeName) {
  2011. case 'node':
  2012. data.nodes.push(child.getAttribute('id'))
  2013. parseNode(child)
  2014. break
  2015. case 'instance_camera':
  2016. data.instanceCameras.push(parseId(child.getAttribute('url')))
  2017. break
  2018. case 'instance_controller':
  2019. data.instanceControllers.push(parseNodeInstance(child))
  2020. break
  2021. case 'instance_light':
  2022. data.instanceLights.push(parseId(child.getAttribute('url')))
  2023. break
  2024. case 'instance_geometry':
  2025. data.instanceGeometries.push(parseNodeInstance(child))
  2026. break
  2027. case 'instance_node':
  2028. data.instanceNodes.push(parseId(child.getAttribute('url')))
  2029. break
  2030. case 'matrix':
  2031. array = parseFloats(child.textContent)
  2032. data.matrix.multiply(matrix.fromArray(array).transpose())
  2033. data.transforms[child.getAttribute('sid')] = child.nodeName
  2034. break
  2035. case 'translate':
  2036. array = parseFloats(child.textContent)
  2037. vector.fromArray(array)
  2038. data.matrix.multiply(matrix.makeTranslation(vector.x, vector.y, vector.z))
  2039. data.transforms[child.getAttribute('sid')] = child.nodeName
  2040. break
  2041. case 'rotate':
  2042. array = parseFloats(child.textContent)
  2043. const angle = MathUtils.degToRad(array[3])
  2044. data.matrix.multiply(matrix.makeRotationAxis(vector.fromArray(array), angle))
  2045. data.transforms[child.getAttribute('sid')] = child.nodeName
  2046. break
  2047. case 'scale':
  2048. array = parseFloats(child.textContent)
  2049. data.matrix.scale(vector.fromArray(array))
  2050. data.transforms[child.getAttribute('sid')] = child.nodeName
  2051. break
  2052. case 'extra':
  2053. break
  2054. default:
  2055. console.log(child)
  2056. }
  2057. }
  2058. if (hasNode(data.id)) {
  2059. console.warn('THREE.ColladaLoader: There is already a node with ID %s. Exclude current node from further processing.', data.id)
  2060. } else {
  2061. library.nodes[data.id] = data
  2062. }
  2063. return data
  2064. }
  2065. function parseNodeInstance(xml) {
  2066. const data = {
  2067. id: parseId(xml.getAttribute('url')),
  2068. materials: {},
  2069. skeletons: []
  2070. }
  2071. for (let i = 0; i < xml.childNodes.length; i++) {
  2072. const child = xml.childNodes[i]
  2073. switch (child.nodeName) {
  2074. case 'bind_material':
  2075. const instances = child.getElementsByTagName('instance_material')
  2076. for (let j = 0; j < instances.length; j++) {
  2077. const instance = instances[j]
  2078. const symbol = instance.getAttribute('symbol')
  2079. const target = instance.getAttribute('target')
  2080. data.materials[symbol] = parseId(target)
  2081. }
  2082. break
  2083. case 'skeleton':
  2084. data.skeletons.push(parseId(child.textContent))
  2085. break
  2086. default:
  2087. break
  2088. }
  2089. }
  2090. return data
  2091. }
  2092. function buildSkeleton(skeletons, joints) {
  2093. const boneData = []
  2094. const sortedBoneData = []
  2095. let i, j, data
  2096. // a skeleton can have multiple root bones. collada expresses this
  2097. // situtation with multiple "skeleton" tags per controller instance
  2098. for (i = 0; i < skeletons.length; i++) {
  2099. const skeleton = skeletons[i]
  2100. let root
  2101. if (hasNode(skeleton)) {
  2102. root = getNode(skeleton)
  2103. buildBoneHierarchy(root, joints, boneData)
  2104. } else if (hasVisualScene(skeleton)) {
  2105. // handle case where the skeleton refers to the visual scene (#13335)
  2106. const visualScene = library.visualScenes[skeleton]
  2107. const children = visualScene.children
  2108. for (let j = 0; j < children.length; j++) {
  2109. const child = children[j]
  2110. if (child.type === 'JOINT') {
  2111. const root = getNode(child.id)
  2112. buildBoneHierarchy(root, joints, boneData)
  2113. }
  2114. }
  2115. } else {
  2116. console.error('THREE.ColladaLoader: Unable to find root bone of skeleton with ID:', skeleton)
  2117. }
  2118. }
  2119. // sort bone data (the order is defined in the corresponding controller)
  2120. for (i = 0; i < joints.length; i++) {
  2121. for (j = 0; j < boneData.length; j++) {
  2122. data = boneData[j]
  2123. if (data.bone.name === joints[i].name) {
  2124. sortedBoneData[i] = data
  2125. data.processed = true
  2126. break
  2127. }
  2128. }
  2129. }
  2130. // add unprocessed bone data at the end of the list
  2131. for (i = 0; i < boneData.length; i++) {
  2132. data = boneData[i]
  2133. if (data.processed === false) {
  2134. sortedBoneData.push(data)
  2135. data.processed = true
  2136. }
  2137. }
  2138. // setup arrays for skeleton creation
  2139. const bones = []
  2140. const boneInverses = []
  2141. for (i = 0; i < sortedBoneData.length; i++) {
  2142. data = sortedBoneData[i]
  2143. bones.push(data.bone)
  2144. boneInverses.push(data.boneInverse)
  2145. }
  2146. return new Skeleton(bones, boneInverses)
  2147. }
  2148. function buildBoneHierarchy(root, joints, boneData) {
  2149. // setup bone data from visual scene
  2150. root.traverse(function(object) {
  2151. if (object.isBone === true) {
  2152. let boneInverse
  2153. // retrieve the boneInverse from the controller data
  2154. for (let i = 0; i < joints.length; i++) {
  2155. const joint = joints[i]
  2156. if (joint.name === object.name) {
  2157. boneInverse = joint.boneInverse
  2158. break
  2159. }
  2160. }
  2161. if (boneInverse === undefined) {
  2162. // Unfortunately, there can be joints in the visual scene that are not part of the
  2163. // corresponding controller. In this case, we have to create a dummy boneInverse matrix
  2164. // for the respective bone. This bone won't affect any vertices, because there are no skin indices
  2165. // and weights defined for it. But we still have to add the bone to the sorted bone list in order to
  2166. // ensure a correct animation of the model.
  2167. boneInverse = new Matrix4()
  2168. }
  2169. boneData.push({ bone: object, boneInverse: boneInverse, processed: false })
  2170. }
  2171. })
  2172. }
  2173. function buildNode(data) {
  2174. const objects = []
  2175. const matrix = data.matrix
  2176. const nodes = data.nodes
  2177. const type = data.type
  2178. const instanceCameras = data.instanceCameras
  2179. const instanceControllers = data.instanceControllers
  2180. const instanceLights = data.instanceLights
  2181. const instanceGeometries = data.instanceGeometries
  2182. const instanceNodes = data.instanceNodes
  2183. // nodes
  2184. for (let i = 0, l = nodes.length; i < l; i++) {
  2185. objects.push(getNode(nodes[i]))
  2186. }
  2187. // instance cameras
  2188. for (let i = 0, l = instanceCameras.length; i < l; i++) {
  2189. const instanceCamera = getCamera(instanceCameras[i])
  2190. if (instanceCamera !== null) {
  2191. objects.push(instanceCamera.clone())
  2192. }
  2193. }
  2194. // instance controllers
  2195. for (let i = 0, l = instanceControllers.length; i < l; i++) {
  2196. const instance = instanceControllers[i]
  2197. const controller = getController(instance.id)
  2198. const geometries = getGeometry(controller.id)
  2199. const newObjects = buildObjects(geometries, instance.materials)
  2200. const skeletons = instance.skeletons
  2201. const joints = controller.skin.joints
  2202. const skeleton = buildSkeleton(skeletons, joints)
  2203. for (let j = 0, jl = newObjects.length; j < jl; j++) {
  2204. const object = newObjects[j]
  2205. if (object.isSkinnedMesh) {
  2206. object.bind(skeleton, controller.skin.bindMatrix)
  2207. object.normalizeSkinWeights()
  2208. }
  2209. objects.push(object)
  2210. }
  2211. }
  2212. // instance lights
  2213. for (let i = 0, l = instanceLights.length; i < l; i++) {
  2214. const instanceLight = getLight(instanceLights[i])
  2215. if (instanceLight !== null) {
  2216. objects.push(instanceLight.clone())
  2217. }
  2218. }
  2219. // instance geometries
  2220. for (let i = 0, l = instanceGeometries.length; i < l; i++) {
  2221. const instance = instanceGeometries[i]
  2222. // a single geometry instance in collada can lead to multiple object3Ds.
  2223. // this is the case when primitives are combined like triangles and lines
  2224. const geometries = getGeometry(instance.id)
  2225. const newObjects = buildObjects(geometries, instance.materials)
  2226. for (let j = 0, jl = newObjects.length; j < jl; j++) {
  2227. objects.push(newObjects[j])
  2228. }
  2229. }
  2230. // instance nodes
  2231. for (let i = 0, l = instanceNodes.length; i < l; i++) {
  2232. objects.push(getNode(instanceNodes[i]).clone())
  2233. }
  2234. let object
  2235. if (nodes.length === 0 && objects.length === 1) {
  2236. object = objects[0]
  2237. } else {
  2238. object = type === 'JOINT' ? new Bone() : new Group()
  2239. for (let i = 0; i < objects.length; i++) {
  2240. object.add(objects[i])
  2241. }
  2242. }
  2243. object.name = type === 'JOINT' ? data.sid : data.name
  2244. object.matrix.copy(matrix)
  2245. object.matrix.decompose(object.position, object.quaternion, object.scale)
  2246. return object
  2247. }
  2248. const fallbackMaterial = new MeshBasicMaterial({ color: 0xff00ff })
  2249. function resolveMaterialBinding(keys, instanceMaterials) {
  2250. const materials = []
  2251. for (let i = 0, l = keys.length; i < l; i++) {
  2252. const id = instanceMaterials[keys[i]]
  2253. if (id === undefined) {
  2254. console.warn('THREE.ColladaLoader: Material with key %s not found. Apply fallback material.', keys[i])
  2255. materials.push(fallbackMaterial)
  2256. } else {
  2257. materials.push(getMaterial(id))
  2258. }
  2259. }
  2260. return materials
  2261. }
  2262. function buildObjects(geometries, instanceMaterials) {
  2263. const objects = []
  2264. for (const type in geometries) {
  2265. const geometry = geometries[type]
  2266. const materials = resolveMaterialBinding(geometry.materialKeys, instanceMaterials)
  2267. // handle case if no materials are defined
  2268. if (materials.length === 0) {
  2269. if (type === 'lines' || type === 'linestrips') {
  2270. materials.push(new LineBasicMaterial())
  2271. } else {
  2272. materials.push(new MeshPhongMaterial())
  2273. }
  2274. }
  2275. // regard skinning
  2276. const skinning = geometry.data.attributes.skinIndex !== undefined
  2277. // choose between a single or multi materials (material array)
  2278. const material = materials.length === 1 ? materials[0] : materials
  2279. // now create a specific 3D object
  2280. let object
  2281. switch (type) {
  2282. case 'lines':
  2283. object = new LineSegments(geometry.data, material)
  2284. break
  2285. case 'linestrips':
  2286. object = new Line(geometry.data, material)
  2287. break
  2288. case 'triangles':
  2289. case 'polylist':
  2290. if (skinning) {
  2291. object = new SkinnedMesh(geometry.data, material)
  2292. } else {
  2293. object = new Mesh(geometry.data, material)
  2294. }
  2295. break
  2296. }
  2297. objects.push(object)
  2298. }
  2299. return objects
  2300. }
  2301. function hasNode(id) {
  2302. return library.nodes[id] !== undefined
  2303. }
  2304. function getNode(id) {
  2305. return getBuild(library.nodes[id], buildNode)
  2306. }
  2307. // visual scenes
  2308. function parseVisualScene(xml) {
  2309. const data = {
  2310. name: xml.getAttribute('name'),
  2311. children: []
  2312. }
  2313. prepareNodes(xml)
  2314. const elements = getElementsByTagName(xml, 'node')
  2315. for (let i = 0; i < elements.length; i++) {
  2316. data.children.push(parseNode(elements[i]))
  2317. }
  2318. library.visualScenes[xml.getAttribute('id')] = data
  2319. }
  2320. function buildVisualScene(data) {
  2321. const group = new Group()
  2322. group.name = data.name
  2323. const children = data.children
  2324. for (let i = 0; i < children.length; i++) {
  2325. const child = children[i]
  2326. group.add(getNode(child.id))
  2327. }
  2328. return group
  2329. }
  2330. function hasVisualScene(id) {
  2331. return library.visualScenes[id] !== undefined
  2332. }
  2333. function getVisualScene(id) {
  2334. return getBuild(library.visualScenes[id], buildVisualScene)
  2335. }
  2336. // scenes
  2337. function parseScene(xml) {
  2338. const instance = getElementsByTagName(xml, 'instance_visual_scene')[0]
  2339. return getVisualScene(parseId(instance.getAttribute('url')))
  2340. }
  2341. function setupAnimations() {
  2342. const clips = library.clips
  2343. if (isEmpty(clips) === true) {
  2344. if (isEmpty(library.animations) === false) {
  2345. // if there are animations but no clips, we create a default clip for playback
  2346. const tracks = []
  2347. for (const id in library.animations) {
  2348. const animationTracks = getAnimation(id)
  2349. for (let i = 0, l = animationTracks.length; i < l; i++) {
  2350. tracks.push(animationTracks[i])
  2351. }
  2352. }
  2353. animations.push(new AnimationClip('default', -1, tracks))
  2354. }
  2355. } else {
  2356. for (const id in clips) {
  2357. animations.push(getAnimationClip(id))
  2358. }
  2359. }
  2360. }
  2361. // convert the parser error element into text with each child elements text
  2362. // separated by new lines.
  2363. function parserErrorToText(parserError) {
  2364. let result = ''
  2365. const stack = [parserError]
  2366. while (stack.length) {
  2367. const node = stack.shift()
  2368. if (node.nodeType === Node.TEXT_NODE) {
  2369. result += node.textContent
  2370. } else {
  2371. result += '\n'
  2372. stack.push.apply(stack, node.childNodes)
  2373. }
  2374. }
  2375. return result.trim()
  2376. }
  2377. if (text.length === 0) {
  2378. return { scene: new Scene() }
  2379. }
  2380. const xml = new DOMParser().parseFromString(text, 'application/xml')
  2381. const collada = getElementsByTagName(xml, 'COLLADA')[0]
  2382. const parserError = xml.getElementsByTagName('parsererror')[0]
  2383. if (parserError !== undefined) {
  2384. // Chrome will return parser error with a div in it
  2385. const errorElement = getElementsByTagName(parserError, 'div')[0]
  2386. let errorText
  2387. if (errorElement) {
  2388. errorText = errorElement.textContent
  2389. } else {
  2390. errorText = parserErrorToText(parserError)
  2391. }
  2392. console.error('THREE.ColladaLoader: Failed to parse collada file.\n', errorText)
  2393. return null
  2394. }
  2395. // metadata
  2396. const version = collada.getAttribute('version')
  2397. console.log('THREE.ColladaLoader: File version', version)
  2398. const asset = parseAsset(getElementsByTagName(collada, 'asset')[0])
  2399. const textureLoader = new TextureLoader(this.manager)
  2400. textureLoader.setPath(this.resourcePath || path).setCrossOrigin(this.crossOrigin)
  2401. let tgaLoader
  2402. if (TGALoader) {
  2403. tgaLoader = new TGALoader(this.manager)
  2404. tgaLoader.setPath(this.resourcePath || path)
  2405. }
  2406. //
  2407. const tempColor = new Color()
  2408. const animations = []
  2409. let kinematics = {}
  2410. let count = 0
  2411. //
  2412. const library = {
  2413. animations: {},
  2414. clips: {},
  2415. controllers: {},
  2416. images: {},
  2417. effects: {},
  2418. materials: {},
  2419. cameras: {},
  2420. lights: {},
  2421. geometries: {},
  2422. nodes: {},
  2423. visualScenes: {},
  2424. kinematicsModels: {},
  2425. physicsModels: {},
  2426. kinematicsScenes: {}
  2427. }
  2428. parseLibrary(collada, 'library_animations', 'animation', parseAnimation)
  2429. parseLibrary(collada, 'library_animation_clips', 'animation_clip', parseAnimationClip)
  2430. parseLibrary(collada, 'library_controllers', 'controller', parseController)
  2431. parseLibrary(collada, 'library_images', 'image', parseImage)
  2432. parseLibrary(collada, 'library_effects', 'effect', parseEffect)
  2433. parseLibrary(collada, 'library_materials', 'material', parseMaterial)
  2434. parseLibrary(collada, 'library_cameras', 'camera', parseCamera)
  2435. parseLibrary(collada, 'library_lights', 'light', parseLight)
  2436. parseLibrary(collada, 'library_geometries', 'geometry', parseGeometry)
  2437. parseLibrary(collada, 'library_nodes', 'node', parseNode)
  2438. parseLibrary(collada, 'library_visual_scenes', 'visual_scene', parseVisualScene)
  2439. parseLibrary(collada, 'library_kinematics_models', 'kinematics_model', parseKinematicsModel)
  2440. parseLibrary(collada, 'library_physics_models', 'physics_model', parsePhysicsModel)
  2441. parseLibrary(collada, 'scene', 'instance_kinematics_scene', parseKinematicsScene)
  2442. buildLibrary(library.animations, buildAnimation)
  2443. buildLibrary(library.clips, buildAnimationClip)
  2444. buildLibrary(library.controllers, buildController)
  2445. buildLibrary(library.images, buildImage)
  2446. buildLibrary(library.effects, buildEffect)
  2447. buildLibrary(library.materials, buildMaterial)
  2448. buildLibrary(library.cameras, buildCamera)
  2449. buildLibrary(library.lights, buildLight)
  2450. buildLibrary(library.geometries, buildGeometry)
  2451. buildLibrary(library.visualScenes, buildVisualScene)
  2452. setupAnimations()
  2453. setupKinematics()
  2454. const scene = parseScene(getElementsByTagName(collada, 'scene')[0])
  2455. scene.animations = animations
  2456. if (asset.upAxis === 'Y_UP') {
  2457. // bimrocket: Z_UP
  2458. scene.quaternion.setFromEuler(new Euler(-Math.PI / 2, 0, 0))
  2459. }
  2460. scene.scale.multiplyScalar(asset.unit)
  2461. return {
  2462. get animations() {
  2463. console.warn('THREE.ColladaLoader: Please access animations over scene.animations now.')
  2464. return animations
  2465. },
  2466. kinematics: kinematics,
  2467. library: library,
  2468. scene: scene
  2469. }
  2470. }
  2471. }
  2472. export { ColladaLoader }