[Bf-extensions-cvs] [9733e52] temp-x3d_import-T44758: Merge branch 'master' into temp-x3d_import-T44758
Bastien Montagne
noreply at git.blender.org
Sat Sep 19 16:14:06 CEST 2015
Commit: 9733e526cf6c325e8b0e687825817841b50a9246
Author: Bastien Montagne
Date: Sat Sep 19 16:12:32 2015 +0200
Branches: temp-x3d_import-T44758
https://developer.blender.org/rBA9733e526cf6c325e8b0e687825817841b50a9246
Merge branch 'master' into temp-x3d_import-T44758
Note that conflict was rather large here, I think merge is OK (few quick tests
seems to show instanciation is still working), but...
===================================================================
===================================================================
diff --cc io_scene_x3d/import_x3d.py
index 217036b,aec4f89..31125e1
--- a/io_scene_x3d/import_x3d.py
+++ b/io_scene_x3d/import_x3d.py
@@@ -345,8 -381,8 +389,9 @@@ class vrmlNode(object)
self.node_type = node_type
self.parent = parent
self.blendObject = None
+ self.blendData = None
self.x3dNode = None # for x3d import only
+ self.parsed = None # We try to reuse objects in a smart way
if parent:
parent.children.append(self)
@@@ -2549,526 -1939,312 +2558,535 @@@ def importMesh_Cylinder(geom, ancestry
return bpymesh
-def importMesh_Cylinder(geom, ancestry):
- # bpymesh = bpy.data.meshes.new()
- diameter = geom.getFieldAsFloat('radius', 1.0, ancestry)
+def importMesh_Cone(geom, ancestry, bpyima):
+ # Solid ignored
+ # Extra parameter subdivision="n" - how many faces to use
+ n = geom.getFieldAsInt('subdivision', GLOBALS['CIRCLE_DETAIL'], ancestry)
+ radius = geom.getFieldAsFloat('bottomRadius', 1.0, ancestry)
height = geom.getFieldAsFloat('height', 2, ancestry)
+ bottom = geom.getFieldAsBool('bottom', True, ancestry)
+ side = geom.getFieldAsBool('side', True, ancestry)
- # bpymesh = Mesh.Primitives.Cylinder(GLOBALS['CIRCLE_DETAIL'], diameter, height)
+ d = height / 2
+ angle = 2 * pi / n
- bpy.ops.mesh.primitive_cylinder_add(vertices=GLOBALS['CIRCLE_DETAIL'],
- radius=diameter,
- depth=height,
- end_fill_type='NGON',
- view_align=False,
- enter_editmode=False,
- )
+ verts = [(0, d, 0)]
+ verts += [(-radius * sin(angle * i),
+ -d,
+ -radius * cos(angle * i)) for i in range(n)]
+ faces = []
- bpymesh = bpy_ops_add_object_hack()
+ # Side face vertices go: up down right
+ if side:
+ faces += [(1 + (i + 1) % n, 0, 1 + i) for i in range(n)]
+ if bottom:
+ faces += [[i for i in range(n, 0, -1)]]
+
+ bpymesh = bpy.data.meshes.new(name="Cone")
+ bpymesh.from_pydata(verts, [], faces)
+
+ bpymesh.validate(False)
+ if bpyima:
+ loops = []
+ if side:
+ loops += [co for i in range(n)
+ for co in ((i + 1) / n, 0, (i + 0.5) / n, 1, i / n, 0)]
+ if bottom:
+ loops += [0.5 - co / 2 for i in range(n - 1, -1, -1)
+ for co in (sin(angle * i), cos(angle * i))]
+ importMesh_ApplyTextureToLoops(bpymesh, bpyima, loops)
- bpymesh.transform(MATRIX_Z_TO_Y)
+ bpymesh.update()
+ return bpymesh
- # Warning - Rely in the order Blender adds verts
- # not nice design but wont change soon.
- bottom = geom.getFieldAsBool('bottom', True, ancestry)
- side = geom.getFieldAsBool('side', True, ancestry)
- top = geom.getFieldAsBool('top', True, ancestry)
+def importMesh_Box(geom, ancestry, bpyima):
+ # Solid is ignored
+ # No ccw in this element
+ (dx, dy, dz) = geom.getFieldAsFloatTuple('size', (2.0, 2.0, 2.0), ancestry)
+ dx /= 2
+ dy /= 2
+ dz /= 2
+
+ bpymesh = bpy.data.meshes.new(name="Box")
+ bpymesh.vertices.add(8)
+
+ # xz plane at +y, ccw
+ co = (dx, dy, dz, -dx, dy, dz, -dx, dy, -dz, dx, dy, -dz,
+ # xz plane at -y
+ dx, -dy, dz, -dx, -dy, dz, -dx, -dy, -dz, dx, -dy, -dz)
+ bpymesh.vertices.foreach_set('co', co)
+
+ bpymesh.tessfaces.add(6)
+ bpymesh.tessfaces.foreach_set('vertices_raw', (
+ 0, 1, 2, 3, # +y
+ 4, 0, 3, 7, # +x
+ 7, 3, 2, 6, # -z
+ 6, 2, 1, 5, # -x
+ 5, 1, 0, 4, # +z
+ 7, 6, 5, 4)) # -y
+
+ bpymesh.validate(False)
+ if bpyima:
+ d = bpymesh.tessface_uv_textures.new().data
+ for face in d: # No foreach_set for nonscalars
+ face.image = bpyima
+ d.foreach_set('uv_raw', (
+ 1, 0, 0, 0, 0, 1, 1, 1,
+ 0, 0, 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 1, 1, 1))
- if not top: # last vert is top center of tri fan.
- # bpymesh.vertices.delete([(GLOBALS['CIRCLE_DETAIL'] + GLOBALS['CIRCLE_DETAIL']) + 1]) # XXX25
- pass
+ bpymesh.update()
+ return bpymesh
- if not bottom: # second last vert is bottom of triangle fan
- # XXX25
- # bpymesh.vertices.delete([GLOBALS['CIRCLE_DETAIL'] + GLOBALS['CIRCLE_DETAIL']])
- pass
+# -----------------------------------------------------------------------------------
+# Utilities for importShape
+
+
+# Textures are processed elsewhere.
+def appearance_CreateMaterial(vrmlname, mat, ancestry, is_vcol):
+ # Given an X3D material, creates a Blender material.
+ # texture is applied later, in appearance_Create().
+ # All values between 0.0 and 1.0, defaults from VRML docs.
+ bpymat = bpy.data.materials.new(vrmlname)
+ bpymat.ambient = mat.getFieldAsFloat('ambientIntensity', 0.2, ancestry)
+ diff_color = mat.getFieldAsFloatTuple('diffuseColor',
+ [0.8, 0.8, 0.8],
+ ancestry)
+ bpymat.diffuse_color = diff_color
+
+ # NOTE - blender dosnt support emmisive color
+ # Store in mirror color and approximate with emit.
+ emit = mat.getFieldAsFloatTuple('emissiveColor', [0.0, 0.0, 0.0], ancestry)
+ bpymat.mirror_color = emit
+ bpymat.emit = (emit[0] + emit[1] + emit[2]) / 3.0
+
+ shininess = mat.getFieldAsFloat('shininess', 0.2, ancestry)
+ bpymat.specular_hardness = int(1 + (510 * shininess))
+ # 0-1 -> 1-511
+ bpymat.specular_color = mat.getFieldAsFloatTuple('specularColor',
+ [0.0, 0.0, 0.0], ancestry)
+ bpymat.alpha = 1.0 - mat.getFieldAsFloat('transparency', 0.0, ancestry)
+ if bpymat.alpha < 0.999:
+ bpymat.use_transparency = True
+ if is_vcol:
+ bpymat.use_vertex_color_paint = True
+ return bpymat
+
+
+def appearance_CreateDefaultMaterial():
+ # Just applies the X3D defaults. Used for shapes
+ # without explicit material definition
+ # (but possibly with a texture).
+
+ bpymat = bpy.data.materials.new("Material")
+ bpymat.ambient = 0.2
+ bpymat.diffuse_color = [0.8, 0.8, 0.8]
+ bpymat.mirror_color = (0, 0, 0)
+ bpymat.emit = 0
+
+ bpymat.specular_hardness = 103
+ # 0-1 -> 1-511
+ bpymat.specular_color = (0, 0, 0)
+ bpymat.alpha = 1
+ return bpymat
+
+
+def appearance_LoadImageTextureFile(ima_urls, node):
+ bpyima = None
+ for f in ima_urls:
+ dirname = os.path.dirname(node.getFilename())
+ bpyima = image_utils.load_image(f, dirname,
+ place_holder=False,
+ recursive=False,
+ convert_callback=imageConvertCompat)
+ if bpyima:
+ break
- if not side:
- # remove all quads
- # XXX25
- # bpymesh.tessfaces.delete(1, [f for f in bpymesh.tessfaces if len(f) == 4])
- pass
+ return bpyima
- return bpymesh
+def appearance_LoadImageTexture(imageTexture, ancestry, node):
+ # TODO: cache loaded textures...
+ ima_urls = imageTexture.getFieldAsString('url', None, ancestry)
-def importMesh_Cone(geom, ancestry):
- # bpymesh = bpy.data.meshes.new()
- diameter = geom.getFieldAsFloat('bottomRadius', 1.0, ancestry)
- height = geom.getFieldAsFloat('height', 2, ancestry)
+ if ima_urls is None:
+ try:
+ ima_urls = imageTexture.getFieldAsStringArray('url', ancestry)
+ # in some cases we get a list of images.
+ except:
+ ima_urls = None
+ else:
+ if '" "' in ima_urls:
+ # '"foo" "bar"' --> ['foo', 'bar']
+ ima_urls = [w.strip('"') for w in ima_urls.split('" "')]
+ else:
+ ima_urls = [ima_urls]
+ # ima_urls is a list or None
+
+ if ima_urls is None:
+ print("\twarning, image with no URL, this is odd")
+ return None
+ else:
+ bpyima = appearance_LoadImageTextureFile(ima_urls, node)
- # bpymesh = Mesh.Primitives.Cone(GLOBALS['CIRCLE_DETAIL'], diameter, height)
+ if not bpyima:
+ print("ImportX3D warning: unable to load texture", ima_urls)
+ else:
+ # KNOWN BUG; PNGs with a transparent color are not perceived
+ # as transparent. Need alpha channel.
+
+ bpyima.use_alpha = bpyima.depth in {32, 128}
+ return bpyima
+
+
+def appearance_LoadTexture(tex_node, ancestry, node):
+ # Both USE-based caching and desc-based caching
+ # Works for bother ImageTextures and PixelTextures
+
+ # USE-based caching
+ if tex_node.reference:
+ return tex_node.getRealNode().parsed
+
+ # Desc-based caching. It might misfire on multifile models, where the
+ # same desc means different things in different files.
+ # TODO: move caches to file level.
+ desc = tex_node.desc()
+ if desc and desc in texture_cache:
+ bpyima = texture_cache[desc]
+ if tex_node.canHaveReferences():
+ tex_node.parsed = bpyima
+ return bpyima
+
+ # No cached texture, load it.
+ if tex_node.getSpec() == 'ImageTexture':
+ bpyima = appearance_LoadImageTexture(tex_node, ancestry, node)
+ else: # PixelTexture
+ bpyima = appearance_LoadPixelTexture(tex_node, ancestry)
+
+ if bpyima: # Loading can still fail
+ repeat_s = tex_node.getFieldAsBool('repeatS', True, ancestry)
+ bpyima.use_clamp_x = not repeat_s
+ repeat_t = tex_node.getFieldAsBool('repeatT', True, ancestry)
+ bpyima.use_clamp_y = not repeat_t
+
+ # Update the desc-b
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list