floorplanner-fml 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,38 @@
1
+ module Geom
2
+ class Triangle
3
+
4
+ attr_accessor :vertices, :texcoord, :normal
5
+
6
+ def initialize(vertices,texcoord=nil,normal=nil)
7
+ unless vertices.length == 3
8
+ raise "Triangle must consist of exactly 3 vertices"
9
+ end
10
+ @normal = normal || Number3D.new
11
+ @vertices = vertices
12
+ @texcoord = texcoord
13
+ create_normal
14
+ end
15
+
16
+ def flip_normal
17
+ @normal.x = -@normal.x
18
+ @normal.y = -@normal.y
19
+ @normal.z = -@normal.z
20
+ end
21
+
22
+ def clone
23
+ Triangle.new(@vertices.collect{|v| v.clone},@texcoord.collect{|uv| uv.clone})
24
+ end
25
+
26
+ private
27
+ def create_normal
28
+ vn0 = @vertices[0].position.clone
29
+ vn1 = @vertices[1].position.clone
30
+ vn2 = @vertices[2].position.clone
31
+ vn1.minus_eq(vn0)
32
+ vn2.minus_eq(vn0)
33
+ @normal = Number3D.cross(vn1,vn2,@normal)
34
+ @normal.normalize
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,94 @@
1
+ module Geom
2
+ class TriangleMesh
3
+
4
+ attr_accessor(:vertices,:texcoord,:faces,:meshes,:data,:tess)
5
+
6
+ def initialize( vertices=nil, faces=nil, user_data=nil )
7
+ @data = user_data || Hash.new
8
+ @faces = faces || Array.new
9
+ @vertices = vertices || Array.new
10
+ @meshes = Array.new
11
+
12
+ @tess = EarTrim
13
+ end
14
+
15
+ def << (mesh)
16
+ @meshes << mesh
17
+ end
18
+
19
+ def vertices
20
+ result = @meshes.collect {|m| m.vertices}.flatten
21
+ result.empty? ? @vertices : result
22
+ end
23
+
24
+ def faces
25
+ result = @meshes.collect {|m| m.faces}.flatten
26
+ result.empty? ? @faces : result
27
+ end
28
+
29
+ def texcoord
30
+ result = @meshes.collect {|m| m.texcoord}.flatten
31
+ result.empty? ? @texcoord : result
32
+ end
33
+
34
+ def update
35
+ @meshes.each {|m| m.update}
36
+ end
37
+
38
+ def reverse
39
+ faces.each {|f| f.vertices.reverse! }
40
+ end
41
+
42
+ def transform_vertices(transformation)
43
+ ta = transformation.to_a
44
+ m11 = ta[0][0]
45
+ m12 = ta[0][1]
46
+ m13 = ta[0][2]
47
+ m21 = ta[1][0]
48
+ m22 = ta[1][1]
49
+ m23 = ta[1][2]
50
+ m31 = ta[2][0]
51
+ m32 = ta[2][1]
52
+ m33 = ta[2][2]
53
+
54
+ m14 = ta[0][3]
55
+ m24 = ta[1][3]
56
+ m34 = ta[2][3]
57
+
58
+ @vertices.each do |v|
59
+ vx = v.x
60
+ vy = v.y
61
+ vz = v.z
62
+
63
+ tx = vx * m11 + vy * m12 + vz * m13 + m14
64
+ ty = vx * m21 + vy * m22 + vz * m23 + m24
65
+ tz = vx * m31 + vy * m32 + vz * m33 + m34
66
+
67
+ v.x = tx
68
+ v.y = ty
69
+ v.z = tz
70
+ end
71
+ end
72
+
73
+ def bounding_box
74
+ min = Geom::Number3D.new( 1000, 1000, 1000)
75
+ max = Geom::Number3D.new(-1000,-1000,-1000)
76
+
77
+ vertices.each do |v|
78
+ min.x = v.x if v.x < min.x
79
+ min.y = v.y if v.y < min.y
80
+ min.z = v.z if v.z < min.z
81
+
82
+ max.x = v.x if v.x > max.x
83
+ max.y = v.y if v.y > max.y
84
+ max.z = v.z if v.z > max.z
85
+ end
86
+
87
+ { :max => max , :min => min }
88
+ end
89
+
90
+ def merge(other)
91
+ @vertices.concat other.vertices
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,33 @@
1
+ require 'forwardable'
2
+
3
+ module Geom
4
+ class Vertex
5
+ attr_accessor(:position,:normal)
6
+ extend Forwardable
7
+ def_delegators(:@position,
8
+ :x, :y, :z, :x=, :y=, :z=,
9
+ :distance_x, :distance_y, :distance_z, :distance, :to_floats)
10
+ def initialize(x=0.0,y=0.0,z=0.0,normal=nil)
11
+ @position = Number3D.new(x,y,z)
12
+ @normal = normal
13
+ end
14
+
15
+ def == (other)
16
+ @position == other.position
17
+ end
18
+
19
+ def equal?(other,snap)
20
+ @position.x-snap < other.x && @position.x+snap > other.x &&
21
+ @position.y-snap < other.y && @position.y+snap > other.y &&
22
+ @position.z-snap < other.z && @position.z+snap > other.z
23
+ end
24
+
25
+ def clone
26
+ Vertex.new(x,y,z)
27
+ end
28
+
29
+ def to_s
30
+ "#<Geom::Vertex:#{@position.to_s}>"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ module Keyhole
2
+ class Archive < Zip::ZipFile
3
+ DAE_CACHE_PATH = File.join(Floorplanner.config['dae_cache_path'],'dae')
4
+ IMG_CACHE_PATH = File.join(Floorplanner.config['dae_cache_path'],'textures')
5
+
6
+ def dae_path(asset_id)
7
+ FileUtils.mkdir_p DAE_CACHE_PATH
8
+ dae = entries.select{|e| e.name.match(/\.dae$/)}.first
9
+ @relative_dae_path = dae.name
10
+ @dae_path = File.join(
11
+ DAE_CACHE_PATH,
12
+ "#{asset_id}_#{File.basename(dae.name)}"
13
+ )
14
+ dae.extract(@dae_path) unless File.exists?(@dae_path)
15
+ @dae_path
16
+ end
17
+
18
+ def image_path(asset_id,relative_to_dae,relative_out=false)
19
+ FileUtils.mkdir_p IMG_CACHE_PATH
20
+ img_path = File.join(File.dirname(@relative_dae_path),relative_to_dae)
21
+ target_path = File.join(IMG_CACHE_PATH,asset_id)
22
+ tex_path = File.join(target_path,File.basename(img_path))
23
+
24
+ unless File.exists?(tex_path)
25
+ FileUtils.mkdir_p target_path
26
+ zip_image = entries.select{|e| e.name.match(File.basename(img_path)) }.first
27
+ extract( zip_image , tex_path )
28
+ end
29
+ relative_out ? '../textures'+tex_path.gsub(IMG_CACHE_PATH,'') : tex_path
30
+ end
31
+
32
+ def destroy
33
+ File.unlink(@dae_path)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,439 @@
1
+ <?xml version="1.0"?>
2
+ <COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
3
+ <asset>
4
+ <contributor>
5
+ <author>john doe &lt;johnny@floorplanner.com&gt;</author>
6
+ </contributor>
7
+ <created>2006-06-21T21:23:22Z</created>
8
+ <modified>2006-06-21T21:23:22Z</modified>
9
+ <unit meter="1.00" name="meter"/>
10
+ <up_axis>Z_UP</up_axis>
11
+ </asset>
12
+
13
+ <library_cameras>
14
+ <camera id="main-cam">
15
+ <optics>
16
+ <technique_common>
17
+ <perspective>
18
+ <yfov>70</yfov>
19
+ <znear>0.1</znear>
20
+ <zfar>100.0</zfar>
21
+ </perspective>
22
+ </technique_common>
23
+ </optics>
24
+ </camera>
25
+ </library_cameras>
26
+
27
+ <library_materials id="surrounding-materials">
28
+ <material id="walls-material" name="WallsMaterial">
29
+ <instance_effect url="#walls-fx"/>
30
+ </material>
31
+ <material id="windows-material" name="WindowsMaterial">
32
+ <instance_effect url="#windows-fx"/>
33
+ </material>
34
+ <% @areas.each do |area_mesh| %>
35
+ <material id="area_<%= area_mesh.data[:id] %>-material" name="<%= area_mesh.data[:name] %>">
36
+ <instance_effect url="#area_<%= area_mesh.data[:id] %>-fx"/>
37
+ </material>
38
+ <% end %>
39
+ <% unless @xrefs; @assets.each_value do |asset| %>
40
+ <% asset.library_materials.each do |materials| %>
41
+ <%= materials.to_s %>
42
+ <% end %>
43
+ <% end; end %>
44
+ </library_materials>
45
+
46
+ <library_effects id="surrounding-effects">
47
+ <effect id="walls-fx">
48
+ <profile_COMMON>
49
+ <technique>
50
+ <phong>
51
+ <emission>
52
+ <color>0.05 0.05 0.05 1</color>
53
+ </emission>
54
+ <ambient>
55
+ <color>0.15 0.15 0.15 1</color>
56
+ </ambient>
57
+ <diffuse>
58
+ <color>0.9 0.9 0.9 1</color>
59
+ </diffuse>
60
+ <specular>
61
+ <color>0 0 0 1</color>
62
+ </specular>
63
+ <shininess>
64
+ <float>0.0</float>
65
+ </shininess>
66
+ <reflective>
67
+ <color>1 1 1 1</color>
68
+ </reflective>
69
+ <reflectivity>
70
+ <float>0.0</float>
71
+ </reflectivity>
72
+ <transparent>
73
+ <color>1 1 1 1</color>
74
+ </transparent>
75
+ <transparency>
76
+ <float>0.0</float>
77
+ </transparency>
78
+ </phong>
79
+ </technique>
80
+ </profile_COMMON>
81
+ </effect>
82
+ <effect id="windows-fx">
83
+ <profile_COMMON>
84
+ <technique>
85
+ <phong>
86
+ <emission>
87
+ <color>0.0 0.0 0.0 1</color>
88
+ </emission>
89
+ <ambient>
90
+ <color>0.15 0.15 0.15 1</color>
91
+ </ambient>
92
+ <diffuse>
93
+ <color>0.9 0.9 1.0 1</color>
94
+ </diffuse>
95
+ <specular>
96
+ <color>0 0 0 1</color>
97
+ </specular>
98
+ <shininess>
99
+ <float>0.0</float>
100
+ </shininess>
101
+ <reflective>
102
+ <color>1 1 1 1</color>
103
+ </reflective>
104
+ <reflectivity>
105
+ <float>0.2</float>
106
+ </reflectivity>
107
+ <transparent>
108
+ <color>1 1 1 1</color>
109
+ </transparent>
110
+ <transparency>
111
+ <float>0.9</float>
112
+ </transparency>
113
+ </phong>
114
+ </technique>
115
+ </profile_COMMON>
116
+ </effect>
117
+ <% @areas.each do |area_mesh|; id = area_mesh.data[:id].to_s %>
118
+ <effect id="area_<%= id %>-fx" name="<%= area_mesh.data[:name] %>">
119
+ <% if area_mesh.data[:texture] %>
120
+ <extra>
121
+ <technique sid="sunflow">
122
+ <diffuse><%= area_mesh.data[:color].join(' ') %></diffuse>
123
+ </technique>
124
+ </extra>
125
+ <% end %>
126
+ <profile_COMMON>
127
+ <% if area_mesh.data[:texture] %>
128
+ <newparam sid="area_<%= id %>-surface">
129
+ <surface type="2D">
130
+ <init_from>area_<%= id %>-image</init_from>
131
+ </surface>
132
+ </newparam>
133
+ <newparam sid="area_<%= id %>-sampler">
134
+ <sampler2D>
135
+ <source>area_<%= id %>-surface</source>
136
+ </sampler2D>
137
+ </newparam>
138
+ <% end %>
139
+ <technique>
140
+ <phong>
141
+ <emission>
142
+ <color>0.05 0.05 0.05 1</color>
143
+ </emission>
144
+ <ambient>
145
+ <color>0.1 0.1 0.1 1</color>
146
+ </ambient>
147
+ <diffuse>
148
+ <% if area_mesh.data[:texture] %>
149
+ <texture texture="area_<%= id %>-sampler"/>
150
+ <% else %>
151
+ <color><%= area_mesh.data[:color].join(' ') %> 1</color>
152
+ <% end %>
153
+ </diffuse>
154
+ <specular>
155
+ <color>0 0 0 1</color>
156
+ </specular>
157
+ <shininess>
158
+ <float>0.0</float>
159
+ </shininess>
160
+ <reflective>
161
+ <color>1 1 1 1</color>
162
+ </reflective>
163
+ <reflectivity>
164
+ <float>0.0</float>
165
+ </reflectivity>
166
+ <transparent>
167
+ <color>1 1 1 1</color>
168
+ </transparent>
169
+ <transparency>
170
+ <float>0.0</float>
171
+ </transparency>
172
+ </phong>
173
+ </technique>
174
+ </profile_COMMON>
175
+ </effect>
176
+ <% end %>
177
+ <% unless @xrefs; @assets.each_value do |asset| %>
178
+ <% asset.library_effects.each do |effects| %>
179
+ <%= effects.to_s %>
180
+ <% end %>
181
+ <% end; end %>
182
+ </library_effects>
183
+
184
+ <library_images>
185
+ <% @areas.each do |area_mesh|; if area_mesh.data[:texture] %>
186
+ <image id="area_<%= area_mesh.data[:id] %>-image" name="<%= area_mesh.data[:name] %>">
187
+ <init_from><%= Floorplanner.config['area_textures_path'] +
188
+ area_mesh.data[:texture].gsub('textures/2d/','').gsub(/\.swf$/,'.png') %></init_from>
189
+ </image>
190
+ <% end; end %>
191
+
192
+ <% unless @xrefs; @assets.each_value do |asset| %>
193
+ <% asset.library_images.each do |image| %>
194
+ <%= image.to_s %>
195
+ <% end %>
196
+ <% end; end %>
197
+ </library_images>
198
+
199
+ <library_geometries id="surrounding-geometry">
200
+
201
+ <geometry id="walls-geom" name="WallsGeometry">
202
+ <mesh>
203
+ <source id="walls-positions" name="position">
204
+ <float_array id="walls-positions-array" count="<%= @walls.vertices.length*3 %>">
205
+ <%= @walls.vertices.collect {|v| v.to_floats }.join(' ') %>
206
+ </float_array>
207
+
208
+ <technique_common>
209
+ <accessor count="<%= @walls.vertices.length %>" offset="0" source="#walls-positions-array" stride="3">
210
+ <param name="X" type="float"></param>
211
+ <param name="Y" type="float"></param>
212
+ <param name="Z" type="float"></param>
213
+ </accessor>
214
+ </technique_common>
215
+ </source>
216
+
217
+ <vertices id="walls-vertices">
218
+ <input semantic="POSITION" source="#walls-positions"/>
219
+ </vertices>
220
+
221
+ <triangles count="<%= @walls.faces.length %>" material="Walls">
222
+ <input semantic="VERTEX" source="#walls-vertices" offset="0"/>
223
+ <p>
224
+ <%= @walls.faces.collect{|f| f.vertices.collect{|v| @walls.vertices.index(v)}}.flatten.join(' ') %>
225
+ </p>
226
+ </triangles>
227
+ </mesh>
228
+ </geometry>
229
+
230
+ <geometry id="windows-geom" name="WindowsGeometry">
231
+ <%
232
+ windows_vertices = @walls.windows.collect {|w| w.vertices}.flatten
233
+ windows_faces = @walls.windows.collect {|w| w.faces}.flatten
234
+ %>
235
+ <mesh>
236
+ <source id="windows-positions" name="position">
237
+ <float_array id="windows-positions-array" count="<%= @walls.vertices.length*3 %>">
238
+ <%= windows_vertices.collect {|v| v.to_floats }.join(' ') %>
239
+ </float_array>
240
+
241
+ <technique_common>
242
+ <accessor count="<%= windows_vertices.length %>" offset="0" source="#windows-positions-array" stride="3">
243
+ <param name="X" type="float"></param>
244
+ <param name="Y" type="float"></param>
245
+ <param name="Z" type="float"></param>
246
+ </accessor>
247
+ </technique_common>
248
+ </source>
249
+
250
+ <vertices id="windows-vertices">
251
+ <input semantic="POSITION" source="#windows-positions"/>
252
+ </vertices>
253
+
254
+ <triangles count="<%= windows_faces.length %>" material="Window">
255
+ <input semantic="VERTEX" source="#windows-vertices" offset="0"/>
256
+ <p>
257
+ <% offset = 0
258
+ @walls.windows.each do |w|
259
+ %>
260
+ <%= w.faces.collect{|f| f.vertices.collect{|v| w.vertices.index(v) + offset}}.flatten.join(' ') %>
261
+ <% offset += w.vertices.length ; end %>
262
+ </p>
263
+ </triangles>
264
+ </mesh>
265
+ </geometry>
266
+ <% @areas.each do |area_mesh|; id = area_mesh.data[:id] %>
267
+ <geometry id="area_<%= id %>-geom" name="Area_<%= id %>_<%= area_mesh.data[:name] %>-Geometry">
268
+ <mesh>
269
+ <source id="area_<%= id %>-positions" name="position">
270
+
271
+ <float_array id="area_<%= id %>-positions-array" count="<%= area_mesh.vertices.length*3 %>">
272
+ <%= area_mesh.vertices.collect {|v| v.to_floats }.join(' ') %>
273
+ </float_array>
274
+
275
+ <technique_common>
276
+ <accessor count="<%= area_mesh.vertices.length %>" offset="0" source="#area_<%= id %>-positions-array" stride="3">
277
+ <param name="X" type="float"></param>
278
+ <param name="Y" type="float"></param>
279
+ <param name="Z" type="float"></param>
280
+ </accessor>
281
+ </technique_common>
282
+ </source>
283
+
284
+ <source id="area_<%= id %>-uvs" name="texcoord">
285
+ <float_array id="area_<%= id %>-uvs-array" count="<%= area_mesh.texcoord.length %>">
286
+ <%= area_mesh.texcoord.map{|n| [n.u,n.v]}.flatten.join(' ') %>
287
+ </float_array>
288
+ <technique_common>
289
+ <accessor count="44" source="#area_<%= id %>-uvs-array" stride="2">
290
+ <param name="S" type="float"/>
291
+ <param name="T" type="float"/>
292
+ </accessor>
293
+ </technique_common>
294
+ </source>
295
+
296
+ <vertices id="area_<%= id %>-vertices">
297
+ <input semantic="POSITION" source="#area_<%= id %>-positions"/>
298
+ </vertices>
299
+
300
+ <triangles count="<%= area_mesh.faces.length %>" material="<%= "Area_"+id %>">
301
+ <input semantic="VERTEX" source="#area_<%= id %>-vertices" offset="0"/>
302
+ <input semantic="TEXCOORD" source="#area_<%= id %>-uvs" offset="1"/>
303
+ <p>
304
+ <%=
305
+ area_mesh.faces.collect { |f|
306
+ v = f.vertices.collect { |v| area_mesh.vertices.index(v) }
307
+ t = f.texcoord.collect { |t| area_mesh.texcoord.index(t) }
308
+ [v[0],t[0],v[1],t[1],v[2],t[2]]
309
+ }.flatten.join(' ')
310
+ %>
311
+ </p>
312
+ </triangles>
313
+ </mesh>
314
+ </geometry>
315
+ <% end %>
316
+ <% unless @xrefs; @assets.each_value do |asset| %>
317
+ <% asset.library_geometries.each do |geometries| %>
318
+ <%= geometries.to_s %>
319
+ <% end %>
320
+ <% end; end %>
321
+ </library_geometries>
322
+ <% unless @xrefs %>
323
+ <library_nodes>
324
+ <% @assets.each_value do |asset| %>
325
+ <% asset.library_nodes.each do |nodes| %>
326
+ <%= nodes.to_s %>
327
+ <% end %>
328
+ <% end %>
329
+ </library_nodes>
330
+ <% end %>
331
+ <library_visual_scenes>
332
+ <visual_scene id="VisualSceneNode" name="<%= @name %>">
333
+ <extra>
334
+ <technique sid="sunflow">
335
+ <image>
336
+ <resolution>800 600</resolution>
337
+ <aa>0 2</aa>
338
+ <filter>gaussian</filter>
339
+ <sampler>ipr</sampler>
340
+ </image>
341
+ <trace_depths>
342
+ <diffuse>4</diffuse>
343
+ <reflection>2</reflection>
344
+ </trace_depths>
345
+ <gi>
346
+ <type>ambocc</type>
347
+ <bright>1 1 1</bright>
348
+ <dark>0 0 0</dark>
349
+ <samples>64</samples>
350
+ <maxdist>3.0 </maxdist>
351
+ </gi>
352
+ <sunsky>
353
+ <up>0 0 1</up>
354
+ <east>1 0 0</east>
355
+ <sundir>0.2 0.4 0.7</sundir>
356
+ <ground>1 1 1</ground>
357
+ </sunsky>
358
+ </technique>
359
+ </extra>
360
+ <node id="Camera" name="Camera">
361
+ <lookat>
362
+ 9.0 -1.0 1.4
363
+ 8.0 -2.0 1.4
364
+ 0.0 0.0 1.0
365
+ </lookat>
366
+ <instance_camera url="#main-cam"/>
367
+ </node>
368
+ <node id="Walls" name="Walls">
369
+ <instance_geometry url="#walls-geom">
370
+ <bind_material>
371
+ <technique_common>
372
+ <instance_material symbol="Walls" target="#walls-material"/>
373
+ </technique_common>
374
+ </bind_material>
375
+ </instance_geometry>
376
+ </node>
377
+ <node id="Windows" name="Windows">
378
+ <instance_geometry url="#windows-geom">
379
+ <bind_material>
380
+ <technique_common>
381
+ <instance_material symbol="Window" target="#windows-material"/>
382
+ </technique_common>
383
+ </bind_material>
384
+ </instance_geometry>
385
+ </node>
386
+ <node id="Areas" name="Areas">
387
+ <% @areas.each do |area_mesh|; id = area_mesh.data[:id] %>
388
+ <node id="Area_<%= id %>" name="Area_<%= id %>">
389
+ <instance_geometry url="#area_<%= id %>-geom">
390
+ <bind_material>
391
+ <technique_common>
392
+ <instance_material symbol="Area_<%= id %>" target="#area_<%= id %>-material"/>
393
+ </technique_common>
394
+ </bind_material>
395
+ </instance_geometry>
396
+ </node>
397
+ <% if area_mesh.data[:type] == 'generated_area' %>
398
+ <node id="Area_<%= id %>-cap" name="Area_<%= id %>-cap">
399
+ <translate>0.0 0.0 <%= @areas.ceiling_z %></translate>
400
+ <instance_geometry url="#area_<%= id %>-geom">
401
+ <bind_material>
402
+ <technique_common>
403
+ <instance_material symbol="Area_<%= id %>" target="#walls-material"/>
404
+ </technique_common>
405
+ </bind_material>
406
+ </instance_geometry>
407
+ </node>
408
+ <% end %>
409
+ <% end %>
410
+ </node>
411
+ <% @elements.each do |element| %>
412
+ <node name="<%= element[:asset].title %>">
413
+ <translate><%= element[:position].to_floats %></translate>
414
+ <% if element[:matrix] %>
415
+ <matrix><%= element[:matrix].to_a.join ' ' %></matrix>
416
+ <% end %>
417
+ <% if element[:rotation].x > 0 %>
418
+ <rotate sid="rotateX">1 0 0 <%= element[:rotation].x %></rotate>
419
+ <% end %>
420
+ <% if element[:rotation].y > 0 %>
421
+ <rotate sid="rotateY">0 1 0 <%= element[:rotation].y %></rotate>
422
+ <% end %>
423
+ <% if element[:rotation].z > 0 %>
424
+ <rotate sid="rotateZ">0 0 1 <%= element[:rotation].z %></rotate>
425
+ <% end %>
426
+ <scale><%= element[:scale].to_floats %></scale>
427
+ <% if @xrefs %>
428
+ <instance_node url="<%= element[:asset].dae_path %>"/>
429
+ <% else %>
430
+ <%= element[:asset].visual_scene_node.to_s %>
431
+ <% end %>
432
+ </node>
433
+ <% end %>
434
+ </visual_scene>
435
+ </library_visual_scenes>
436
+ <scene>
437
+ <instance_visual_scene url="#VisualSceneNode"/>
438
+ </scene>
439
+ </COLLADA>