source: other-projects/playing-in-the-street/summer-2013/trunk/Playing-in-the-Street-WPF/Content/Web/mrdoob-three.js-4862f5f/utils/exporters/blender/2.65/scripts/addons/io_mesh_threejs/import_threejs.py@ 28897

Last change on this file since 28897 was 28897, checked in by davidb, 10 years ago

GUI front-end to server base plus web page content

File size: 16.2 KB
Line 
1# ##### BEGIN GPL LICENSE BLOCK #####
2#
3# This program is free software; you can redistribute it and/or
4# modify it under the terms of the GNU General Public License
5# as published by the Free Software Foundation; either version 2
6# of the License, or (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program; if not, write to the Free Software Foundation,
15# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16#
17# ##### END GPL LICENSE BLOCK #####
18
19"""
20Blender importer for Three.js (ASCII JSON format).
21
22"""
23
24import os
25import time
26import json
27import bpy
28import mathutils
29from mathutils.geometry import tessellate_polygon
30from bpy_extras.image_utils import load_image
31
32# #####################################################
33# Generators
34# #####################################################
35def setColor(c, t):
36 c.r = t[0]
37 c.g = t[1]
38 c.b = t[2]
39
40def create_texture(filename, modelpath):
41 name = filename
42 texture = bpy.data.textures.new(name, type='IMAGE')
43
44 image = load_image(filename, modelpath)
45 has_data = False
46
47 if image:
48 texture.image = image
49 has_data = image.has_data
50
51 return texture
52
53def create_materials(data, modelpath):
54 materials = []
55 materials_data = data.get("materials", [])
56
57 for i, m in enumerate(materials_data):
58
59 name = m.get("DbgName", "material_%d" % i)
60
61 colorAmbient = m.get("colorAmbient", None)
62 colorDiffuse = m.get("colorDiffuse", None)
63 colorSpecular = m.get("colorSpecular", None)
64 alpha = m.get("transparency", 1.0)
65 specular_hardness = m.get("specularCoef", 0)
66
67 mapDiffuse = m.get("mapDiffuse", None)
68 mapLightmap = m.get("mapLightmap", None)
69
70 vertexColorsType = m.get("vertexColors", False)
71
72 useVertexColors = False
73 if vertexColorsType:
74 useVertexColors = True
75
76 material = bpy.data.materials.new(name)
77
78 material.THREE_useVertexColors = useVertexColors
79
80 if colorDiffuse:
81 setColor(material.diffuse_color, colorDiffuse)
82 material.diffuse_intensity = 1.0
83
84 if colorSpecular:
85 setColor(material.specular_color, colorSpecular)
86 material.specular_intensity = 1.0
87
88 if alpha < 1.0:
89 material.alpha = alpha
90 material.use_transparency = True
91
92 if specular_hardness:
93 material.specular_hardness = specular_hardness
94
95 if mapDiffuse:
96 texture = create_texture(mapDiffuse, modelpath)
97 mtex = material.texture_slots.add()
98 mtex.texture = texture
99 mtex.texture_coords = 'UV'
100 mtex.use = True
101 mtex.use_map_color_diffuse = True
102
103 material.active_texture = texture
104
105 materials.append(material)
106
107 return materials
108
109def create_mesh_object(name, vertices, materials, face_data, flipYZ, recalculate_normals):
110
111 faces = face_data["faces"]
112 vertexNormals = face_data["vertexNormals"]
113 vertexColors = face_data["vertexColors"]
114 vertexUVs = face_data["vertexUVs"]
115 faceMaterials = face_data["materials"]
116 faceColors = face_data["faceColors"]
117
118 edges = []
119
120 # Create a new mesh
121
122 me = bpy.data.meshes.new(name)
123 me.from_pydata(vertices, edges, faces)
124
125 # Handle normals
126
127 if not recalculate_normals:
128 me.update(calc_edges = True)
129
130 if face_data["hasVertexNormals"]:
131
132 print("setting vertex normals")
133 me.update(calc_tessface = True)
134
135 for fi in range(len(faces)):
136
137 if vertexNormals[fi]:
138
139 #print("setting face %i with %i vertices" % (fi, len(normals[fi])))
140
141 # if me.update() is called after setting vertex normals
142 # setting face.use_smooth overrides these normals
143 # - this fixes weird shading artefacts (seems to come from sharing
144 # of vertices between faces, didn't find a way how to set vertex normals
145 # per face use of vertex as opposed to per vertex),
146 # - probably this just overrides all custom vertex normals
147 # - to preserve vertex normals from the original data
148 # call me.update() before setting them
149
150 me.tessfaces[fi].use_smooth = True
151
152 if not recalculate_normals:
153 for j in range(len(vertexNormals[fi])):
154
155 vertexNormal = vertexNormals[fi][j]
156
157 x = vertexNormal[0]
158 y = vertexNormal[1]
159 z = vertexNormal[2]
160
161 if flipYZ:
162 tmp = y
163 y = -z
164 z = tmp
165
166 # flip normals (this make them look consistent with the original before export)
167
168 #x = -x
169 #y = -y
170 #z = -z
171
172 vi = me.tessfaces[fi].vertices[j]
173
174 me.vertices[vi].normal.x = x
175 me.vertices[vi].normal.y = y
176 me.vertices[vi].normal.z = z
177
178 if recalculate_normals:
179 me.update(calc_edges = True)
180
181 # Handle colors
182
183 if face_data["hasVertexColors"]:
184
185 print("setting vertex colors")
186
187 me.vertex_colors.new("vertex_color_layer_0")
188
189 for fi in range(len(faces)):
190
191 if vertexColors[fi]:
192
193 face_colors = me.vertex_colors[0].data[fi]
194 face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
195
196 for vi in range(len(vertexColors[fi])):
197
198 r = vertexColors[fi][vi][0]
199 g = vertexColors[fi][vi][1]
200 b = vertexColors[fi][vi][2]
201
202 face_colors[vi].r = r
203 face_colors[vi].g = g
204 face_colors[vi].b = b
205
206 elif face_data["hasFaceColors"]:
207
208 print("setting vertex colors from face colors")
209
210 me.vertex_colors.new("vertex_color_layer_0")
211
212 for fi in range(len(faces)):
213
214 if faceColors[fi]:
215
216 r = faceColors[fi][0]
217 g = faceColors[fi][1]
218 b = faceColors[fi][2]
219
220 face_colors = me.vertex_colors[0].data[fi]
221 face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
222
223 for vi in range(len(faces[fi])):
224
225 face_colors[vi].r = r
226 face_colors[vi].g = g
227 face_colors[vi].b = b
228
229 # Handle uvs
230
231 if face_data["hasVertexUVs"]:
232
233 print("setting vertex uvs")
234
235 for li, layer in enumerate(vertexUVs):
236
237 me.uv_textures.new("uv_layer_%d" % li)
238
239 for fi in range(len(faces)):
240
241 if layer[fi]:
242
243 uv_face = me.uv_textures[li].data[fi]
244 face_uvs = uv_face.uv1, uv_face.uv2, uv_face.uv3, uv_face.uv4
245
246 for vi in range(len(layer[fi])):
247
248 u = layer[fi][vi][0]
249 v = layer[fi][vi][1]
250
251 face_uvs[vi].x = u
252 face_uvs[vi].y = v
253
254 active_texture = materials[faceMaterials[fi]].active_texture
255
256 if active_texture:
257 uv_face.image = active_texture.image
258
259
260 # Handle materials # 1
261
262 if face_data["hasMaterials"]:
263
264
265 print("setting materials (mesh)")
266
267 for m in materials:
268
269 me.materials.append(m)
270
271 print("setting materials (faces)")
272 me.update(calc_tessface = True)
273
274 for fi in range(len(faces)):
275
276 if faceMaterials[fi] >= 0:
277
278 me.tessfaces[fi].material_index = faceMaterials[fi]
279
280 # Create a new object
281
282 ob = bpy.data.objects.new(name, me)
283 ob.data = me # link the mesh data to the object
284
285
286 scene = bpy.context.scene # get the current scene
287 scene.objects.link(ob) # link the object into the scene
288
289 ob.location = scene.cursor_location # position object at 3d-cursor
290
291
292# #####################################################
293# Faces
294# #####################################################
295
296def extract_faces(data):
297
298 result = {
299 "faces" : [],
300 "materials" : [],
301 "faceUVs" : [],
302 "vertexUVs" : [],
303 "faceNormals" : [],
304 "vertexNormals" : [],
305 "faceColors" : [],
306 "vertexColors" : [],
307
308 "hasVertexNormals" : False,
309 "hasVertexUVs" : False,
310 "hasVertexColors" : False,
311 "hasFaceColors" : False,
312 "hasMaterials" : False
313 }
314
315 faces = data.get("faces", [])
316 normals = data.get("normals", [])
317 colors = data.get("colors", [])
318
319 offset = 0
320 zLength = len(faces)
321
322 # disregard empty arrays
323
324 nUvLayers = 0
325
326 for layer in data["uvs"]:
327
328 if len(layer) > 0:
329 nUvLayers += 1
330 result["faceUVs"].append([])
331 result["vertexUVs"].append([])
332
333
334 while ( offset < zLength ):
335
336 type = faces[ offset ]
337 offset += 1
338
339 isQuad = isBitSet( type, 0 )
340 hasMaterial = isBitSet( type, 1 )
341 hasFaceUv = isBitSet( type, 2 )
342 hasFaceVertexUv = isBitSet( type, 3 )
343 hasFaceNormal = isBitSet( type, 4 )
344 hasFaceVertexNormal = isBitSet( type, 5 )
345 hasFaceColor = isBitSet( type, 6 )
346 hasFaceVertexColor = isBitSet( type, 7 )
347
348 #print("type", type, "bits", isQuad, hasMaterial, hasFaceUv, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor)
349
350 result["hasVertexUVs"] = result["hasVertexUVs"] or hasFaceVertexUv
351 result["hasVertexNormals"] = result["hasVertexNormals"] or hasFaceVertexNormal
352 result["hasVertexColors"] = result["hasVertexColors"] or hasFaceVertexColor
353 result["hasFaceColors"] = result["hasFaceColors"] or hasFaceColor
354 result["hasMaterials"] = result["hasMaterials"] or hasMaterial
355
356 # vertices
357
358 if isQuad:
359
360 a = faces[ offset ]
361 offset += 1
362
363 b = faces[ offset ]
364 offset += 1
365
366 c = faces[ offset ]
367 offset += 1
368
369 d = faces[ offset ]
370 offset += 1
371
372 face = [a, b, c, d]
373
374 nVertices = 4
375
376 else:
377
378 a = faces[ offset ]
379 offset += 1
380
381 b = faces[ offset ]
382 offset += 1
383
384 c = faces[ offset ]
385 offset += 1
386
387 face = [a, b, c]
388
389 nVertices = 3
390
391 result["faces"].append(face)
392
393 # material
394
395 if hasMaterial:
396
397 materialIndex = faces[ offset ]
398 offset += 1
399
400 else:
401
402 materialIndex = -1
403
404 result["materials"].append(materialIndex)
405
406 # uvs
407
408 for i in range(nUvLayers):
409
410 faceUv = None
411
412 if hasFaceUv:
413
414 uvLayer = data["uvs"][ i ]
415
416 uvIndex = faces[ offset ]
417 offset += 1
418
419 u = uvLayer[ uvIndex * 2 ]
420 v = uvLayer[ uvIndex * 2 + 1 ]
421
422 faceUv = [u, v]
423
424 result["faceUVs"][i].append(faceUv)
425
426
427 if hasFaceVertexUv:
428
429 uvLayer = data["uvs"][ i ]
430
431 vertexUvs = []
432
433 for j in range(nVertices):
434
435 uvIndex = faces[ offset ]
436 offset += 1
437
438 u = uvLayer[ uvIndex * 2 ]
439 v = uvLayer[ uvIndex * 2 + 1 ]
440
441 vertexUvs.append([u, v])
442
443 result["vertexUVs"][i].append(vertexUvs)
444
445
446 if hasFaceNormal:
447
448 normalIndex = faces[ offset ] * 3
449 offset += 1
450
451 x = normals[ normalIndex ]
452 y = normals[ normalIndex + 1 ]
453 z = normals[ normalIndex + 2 ]
454
455 faceNormal = [x, y, z]
456
457 else:
458
459 faceNormal = None
460
461 result["faceNormals"].append(faceNormal)
462
463
464 if hasFaceVertexNormal:
465
466 vertexNormals = []
467
468 for j in range(nVertices):
469
470 normalIndex = faces[ offset ] * 3
471 offset += 1
472
473 x = normals[ normalIndex ]
474 y = normals[ normalIndex + 1 ]
475 z = normals[ normalIndex + 2 ]
476
477 vertexNormals.append( [x, y, z] )
478
479
480 else:
481
482 vertexNormals = None
483
484 result["vertexNormals"].append(vertexNormals)
485
486
487 if hasFaceColor:
488
489 colorIndex = faces[ offset ]
490 offset += 1
491
492 faceColor = hexToTuple( colors[ colorIndex ] )
493
494 else:
495
496 faceColor = None
497
498 result["faceColors"].append(faceColor)
499
500
501 if hasFaceVertexColor:
502
503 vertexColors = []
504
505 for j in range(nVertices):
506
507 colorIndex = faces[ offset ]
508 offset += 1
509
510 color = hexToTuple( colors[ colorIndex ] )
511 vertexColors.append( color )
512
513 else:
514
515 vertexColors = None
516
517 result["vertexColors"].append(vertexColors)
518
519
520 return result
521
522# #####################################################
523# Utils
524# #####################################################
525
526def hexToTuple( hexColor ):
527 r = (( hexColor >> 16 ) & 0xff) / 255.0
528 g = (( hexColor >> 8 ) & 0xff) / 255.0
529 b = ( hexColor & 0xff) / 255.0
530 return (r, g, b)
531
532def isBitSet(value, position):
533 return value & ( 1 << position )
534
535def splitArray(data, chunkSize):
536 result = []
537 chunk = []
538 for i in range(len(data)):
539 if i > 0 and i % chunkSize == 0:
540 result.append(chunk)
541 chunk = []
542 chunk.append(data[i])
543 result.append(chunk)
544 return result
545
546
547def extract_json_string(text):
548 marker_begin = "var model ="
549 marker_end = "postMessage"
550
551 start = text.find(marker_begin) + len(marker_begin)
552 end = text.find(marker_end)
553 end = text.rfind("}", start, end)
554 return text[start:end+1].strip()
555
556def get_name(filepath):
557 return os.path.splitext(os.path.basename(filepath))[0]
558
559def get_path(filepath):
560 return os.path.dirname(filepath)
561
562# #####################################################
563# Parser
564# #####################################################
565
566def load(operator, context, filepath, option_flip_yz = True, recalculate_normals = True, option_worker = False):
567
568 print('\nimporting %r' % filepath)
569
570 time_main = time.time()
571
572 print("\tparsing JSON file...")
573
574 time_sub = time.time()
575
576 file = open(filepath, 'rU')
577 rawcontent = file.read()
578 file.close()
579
580 if option_worker:
581 json_string = extract_json_string(rawcontent)
582 else:
583 json_string = rawcontent
584 data = json.loads( json_string )
585
586 time_new = time.time()
587
588 print('parsing %.4f sec' % (time_new - time_sub))
589
590 time_sub = time_new
591
592 # flip YZ
593
594 vertices = splitArray(data["vertices"], 3)
595
596 if option_flip_yz:
597 vertices[:] = [(v[0], -v[2], v[1]) for v in vertices]
598
599 # extract faces
600
601 face_data = extract_faces(data)
602
603 # deselect all
604
605 bpy.ops.object.select_all(action='DESELECT')
606
607 nfaces = len(face_data["faces"])
608 nvertices = len(vertices)
609 nnormals = len(data.get("normals", [])) / 3
610 ncolors = len(data.get("colors", [])) / 3
611 nuvs = len(data.get("uvs", [])) / 2
612 nmaterials = len(data.get("materials", []))
613
614 print('\tbuilding geometry...\n\tfaces:%i, vertices:%i, vertex normals: %i, vertex uvs: %i, vertex colors: %i, materials: %i ...' % (
615 nfaces, nvertices, nnormals, nuvs, ncolors, nmaterials ))
616
617 # Create materials
618
619 materials = create_materials(data, get_path(filepath))
620
621 # Create new obj
622
623 create_mesh_object(get_name(filepath), vertices, materials, face_data, option_flip_yz, recalculate_normals)
624
625 scene = bpy.context.scene
626 scene.update()
627
628 time_new = time.time()
629
630 print('finished importing: %r in %.4f sec.' % (filepath, (time_new - time_main)))
631 return {'FINISHED'}
632
633
634if __name__ == "__main__":
635 register()
Note: See TracBrowser for help on using the repository browser.