@things-factory/scene-visualizer 6.0.1 → 6.0.5

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