Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2015-06-26 19:39:23 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2015-06-26 19:39:23 +0300
commit1b1ad4665b852c1c52dcbdb0176cf2eb7f0d88f8 (patch)
tree93b9d036981999f6235e6c22a85b6d8ffee9f3a5 /io_scene_x3d
parent7051ad3028c3ee46decd8d58e95f03c97e7c3cb1 (diff)
Fix T45203: X3D import issues: no support of instancing!!!
Previously, that script whould create an object (two, actually!), mesh, material etc. for every 'Shape' node, even when x3d format has intancing capabilities. That would made importing files with many copies of same object insanely long. Now we support instances of objects, geometry (aka meshes), materials (aka appearance) and images, should be enough for now. Also, fixed some old cruft like still using tessface stuff in a few minor places and such.
Diffstat (limited to 'io_scene_x3d')
-rw-r--r--io_scene_x3d/__init__.py2
-rw-r--r--io_scene_x3d/import_x3d.py381
2 files changed, 200 insertions, 183 deletions
diff --git a/io_scene_x3d/__init__.py b/io_scene_x3d/__init__.py
index c43e00a8..78851a62 100644
--- a/io_scene_x3d/__init__.py
+++ b/io_scene_x3d/__init__.py
@@ -21,7 +21,7 @@
bl_info = {
"name": "Web3D X3D/VRML2 format",
"author": "Campbell Barton, Bart, Bastien Montagne",
- "version": (1, 0, 1),
+ "version": (1, 1, 0),
"blender": (2, 74, 0),
"location": "File > Import-Export",
"description": "Import-Export X3D, Import VRML2",
diff --git a/io_scene_x3d/import_x3d.py b/io_scene_x3d/import_x3d.py
index 840f6354..aec4f890 100644
--- a/io_scene_x3d/import_x3d.py
+++ b/io_scene_x3d/import_x3d.py
@@ -370,6 +370,7 @@ class vrmlNode(object):
'lineno',
'filename',
'blendObject',
+ 'blendData',
'DEF_NAMESPACE',
'ROUTE_IPO_NAMESPACE',
'PROTO_NAMESPACE',
@@ -380,6 +381,7 @@ class vrmlNode(object):
self.node_type = node_type
self.parent = parent
self.blendObject = None
+ self.blendData = None
self.x3dNode = None # for x3d import only
if parent:
parent.children.append(self)
@@ -2037,197 +2039,212 @@ def importMesh_Box(geom, ancestry):
def importShape(node, ancestry, global_matrix):
- vrmlname = node.getDefName()
- if not vrmlname:
- vrmlname = 'Shape'
-
- # works 100% in vrml, but not x3d
- #appr = node.getChildByName('appearance') # , 'Appearance'
- #geom = node.getChildByName('geometry') # , 'IndexedFaceSet'
-
- # Works in vrml and x3d
- appr = node.getChildBySpec('Appearance')
- geom = node.getChildBySpec(['IndexedFaceSet', 'IndexedLineSet', 'PointSet', 'Sphere', 'Box', 'Cylinder', 'Cone'])
-
- # For now only import IndexedFaceSet's
- if geom:
- bpymat = None
- bpyima = None
- texmtx = None
-
- image_depth = 0 # so we can set alpha face flag later
- is_vcol = (geom.getChildBySpec('Color') is not None)
-
- if appr:
-
- #mat = appr.getChildByName('material') # 'Material'
- #ima = appr.getChildByName('texture') # , 'ImageTexture'
- #if ima and ima.getSpec() != 'ImageTexture':
- # print('\tWarning: texture type "%s" is not supported' % ima.getSpec())
- # ima = None
- # textx = appr.getChildByName('textureTransform')
-
- mat = appr.getChildBySpec('Material')
- ima = appr.getChildBySpec('ImageTexture')
+ def apply_texmtx(blendata, texmtx):
+ for luv in bpydata.uv_layers.active.data:
+ luv.uv = texmtx * luv.uv
- textx = appr.getChildBySpec('TextureTransform')
+ bpyob = node.getRealNode().blendObject
- if textx:
- texmtx = translateTexTransform(textx, ancestry)
-
- # print(mat, ima)
- if mat or ima:
-
- if not mat:
- mat = ima # This is a bit dumb, but just means we use default values for all
-
- # 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)
- bpymat.diffuse_color = mat.getFieldAsFloatTuple('diffuseColor', [0.8, 0.8, 0.8], ancestry)
-
- # 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
+ if bpyob is not None:
+ bpyob = node.blendData = node.blendObject = bpyob.copy()
+ bpy.context.scene.objects.link(bpyob).select = True
+ else:
+ vrmlname = node.getDefName()
+ if not vrmlname:
+ vrmlname = 'Shape'
+
+ # works 100% in vrml, but not x3d
+ #appr = node.getChildByName('appearance') # , 'Appearance'
+ #geom = node.getChildByName('geometry') # , 'IndexedFaceSet'
+
+ # Works in vrml and x3d
+ appr = node.getChildBySpec('Appearance')
+ geom = node.getChildBySpec(['IndexedFaceSet', 'IndexedLineSet', 'PointSet', 'Sphere', 'Box', 'Cylinder', 'Cone'])
+
+ # For now only import IndexedFaceSet's
+ if geom:
+ bpymat = None
+ bpyima = None
+ texmtx = None
+
+ image_depth = 0 # so we can set alpha face flag later
+ is_vcol = (geom.getChildBySpec('Color') is not None)
+
+ if appr:
+ #mat = appr.getChildByName('material') # 'Material'
+ #ima = appr.getChildByName('texture') # , 'ImageTexture'
+ #if ima and ima.getSpec() != 'ImageTexture':
+ # print('\tWarning: texture type "%s" is not supported' % ima.getSpec())
+ # ima = None
+ # textx = appr.getChildByName('textureTransform')
+
+ mat = appr.getChildBySpec('Material')
+ ima = appr.getChildBySpec('ImageTexture')
+
+ textx = appr.getChildBySpec('TextureTransform')
+
+ if textx:
+ texmtx = translateTexTransform(textx, ancestry)
+
+ bpymat = appr.getRealNode().blendData
+
+ if bpymat is None:
+ # print(mat, ima)
+ if mat or ima:
+ if not mat:
+ mat = ima # This is a bit dumb, but just means we use default values for all
+
+ # 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)
+ bpymat.diffuse_color = mat.getFieldAsFloatTuple('diffuseColor', [0.8, 0.8, 0.8], ancestry)
+
+ # 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
+
+ bpymat.specular_hardness = int(1 + (510 * mat.getFieldAsFloat('shininess', 0.2, ancestry))) # 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
- bpymat.specular_hardness = int(1 + (510 * mat.getFieldAsFloat('shininess', 0.2, ancestry))) # 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
+ if ima:
+ bpyima = ima.getRealNode().blendData
- if ima:
- ima_urls = ima.getFieldAsString('url', None, ancestry)
+ if bpyima is None:
+ ima_urls = ima.getFieldAsString('url', None, ancestry)
- if ima_urls is None:
- try:
- ima_urls = ima.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")
+ if ima_urls is None:
+ try:
+ ima_urls = ima.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")
+ else:
+ for f in ima_urls:
+ bpyima = image_utils.load_image(f, os.path.dirname(node.getFilename()), place_holder=False,
+ recursive=False, convert_callback=imageConvertCompat)
+ if bpyima:
+ break
+
+ if bpyima:
+ texture = bpy.data.textures.new(bpyima.name, 'IMAGE')
+ texture.image = bpyima
+
+ # Adds textures for materials (rendering)
+ try:
+ image_depth = bpyima.depth
+ except:
+ image_depth = -1
+
+ mtex = bpymat.texture_slots.add()
+ mtex.texture = texture
+
+ mtex.texture_coords = 'UV'
+ mtex.use_map_diffuse = True
+
+ if image_depth in {32, 128}:
+ bpymat.use_transparency = True
+ mtex.use_map_alpha = True
+ mtex.alpha_factor = 0.0
+
+ ima_repS = ima.getFieldAsBool('repeatS', True, ancestry)
+ ima_repT = ima.getFieldAsBool('repeatT', True, ancestry)
+
+ # To make this work properly we'd need to scale the UV's too, better to ignore th
+ # texture.repeat = max(1, ima_repS * 512), max(1, ima_repT * 512)
+
+ if not ima_repS:
+ bpyima.use_clamp_x = True
+ if not ima_repT:
+ bpyima.use_clamp_y = True
+ elif ima:
+ bpyima = ima.getRealNode().blendData
+
+ appr.blendData = bpymat
+ if ima:
+ ima.blendData = bpyima
+
+ bpydata = geom.getRealNode().blendData
+ if bpydata is None:
+ geom_spec = geom.getSpec()
+ ccw = True
+ if geom_spec == 'IndexedFaceSet':
+ bpydata, ccw = importMesh_IndexedFaceSet(geom, bpyima, ancestry)
+ elif geom_spec == 'IndexedLineSet':
+ bpydata = importMesh_IndexedLineSet(geom, ancestry)
+ elif geom_spec == 'PointSet':
+ bpydata = importMesh_PointSet(geom, ancestry)
+ elif geom_spec == 'Sphere':
+ bpydata = importMesh_Sphere(geom, ancestry)
+ elif geom_spec == 'Box':
+ bpydata = importMesh_Box(geom, ancestry)
+ elif geom_spec == 'Cylinder':
+ bpydata = importMesh_Cylinder(geom, ancestry)
+ elif geom_spec == 'Cone':
+ bpydata = importMesh_Cone(geom, ancestry)
else:
- bpyima = None
- for f in ima_urls:
- bpyima = image_utils.load_image(f, os.path.dirname(node.getFilename()), place_holder=False, recursive=False, convert_callback=imageConvertCompat)
- if bpyima:
- break
+ print('\tWarning: unsupported type "%s"' % geom_spec)
+ return
- if bpyima:
- texture = bpy.data.textures.new(bpyima.name, 'IMAGE')
- texture.image = bpyima
+ if bpydata:
+ vrmlname = vrmlname + geom_spec
+ bpydata.name = vrmlname
- # Adds textures for materials (rendering)
- try:
- image_depth = bpyima.depth
- except:
- image_depth = -1
+ if type(bpydata) == bpy.types.Mesh:
+ is_solid = geom.getFieldAsBool('solid', True, ancestry)
+ creaseAngle = geom.getFieldAsFloat('creaseAngle', None, ancestry)
- mtex = bpymat.texture_slots.add()
- mtex.texture = texture
+ if creaseAngle is not None:
+ bpydata.auto_smooth_angle = creaseAngle
+ bpydata.use_auto_smooth = True
- mtex.texture_coords = 'UV'
- mtex.use_map_diffuse = True
+ # Only ever 1 material per shape
+ if bpymat:
+ bpydata.materials.append(bpymat)
- if image_depth in {32, 128}:
- bpymat.use_transparency = True
- mtex.use_map_alpha = True
- mtex.alpha_factor = 0.0
-
- ima_repS = ima.getFieldAsBool('repeatS', True, ancestry)
- ima_repT = ima.getFieldAsBool('repeatT', True, ancestry)
-
- # To make this work properly we'd need to scale the UV's too, better to ignore th
- # texture.repeat = max(1, ima_repS * 512), max(1, ima_repT * 512)
-
- if not ima_repS:
- bpyima.use_clamp_x = True
- if not ima_repT:
- bpyima.use_clamp_y = True
-
- bpydata = None
- geom_spec = geom.getSpec()
- ccw = True
- if geom_spec == 'IndexedFaceSet':
- bpydata, ccw = importMesh_IndexedFaceSet(geom, bpyima, ancestry)
- elif geom_spec == 'IndexedLineSet':
- bpydata = importMesh_IndexedLineSet(geom, ancestry)
- elif geom_spec == 'PointSet':
- bpydata = importMesh_PointSet(geom, ancestry)
- elif geom_spec == 'Sphere':
- bpydata = importMesh_Sphere(geom, ancestry)
- elif geom_spec == 'Box':
- bpydata = importMesh_Box(geom, ancestry)
- elif geom_spec == 'Cylinder':
- bpydata = importMesh_Cylinder(geom, ancestry)
- elif geom_spec == 'Cone':
- bpydata = importMesh_Cone(geom, ancestry)
- else:
- print('\tWarning: unsupported type "%s"' % geom_spec)
- return
+ if bpydata.uv_layers:
+ if texmtx:
+ # Apply texture transform?
+ apply_texmtx(blendata, texmtx)
+ # Done transforming the texture
- if bpydata:
- vrmlname = vrmlname + geom_spec
+ # Must be here and not in IndexedFaceSet because it needs an object for the flip func. Messy :/
+ if not ccw:
+ # bpydata.flipNormals()
+ # XXX25
+ pass
- bpydata.name = vrmlname
+ # else could be a curve for example
- bpyob = node.blendObject = bpy.data.objects.new(vrmlname, bpydata)
- bpy.context.scene.objects.link(bpyob).select = True
+ # if texmtx is defined, we need specific UVMap, hence a copy of the mesh...
+ elif texmtx and blendata.uv_layers:
+ bpydata = bpydata.copy()
+ apply_texmtx(blendata, texmtx)
- if type(bpydata) == bpy.types.Mesh:
- is_solid = geom.getFieldAsBool('solid', True, ancestry)
- creaseAngle = geom.getFieldAsFloat('creaseAngle', None, ancestry)
-
- if creaseAngle is not None:
- bpydata.auto_smooth_angle = creaseAngle
- bpydata.use_auto_smooth = True
-
- # Only ever 1 material per shape
- if bpymat:
- bpydata.materials.append(bpymat)
-
- if bpydata.tessface_uv_textures:
-
- if image_depth in {32, 128}: # set the faces alpha flag?
- transp = Mesh.FaceTranspModes.ALPHA
- for f in bpydata.tessface_uv_textures.active.data:
- f.blend_type = 'ALPHA'
-
- if texmtx:
- # Apply texture transform?
- uv_copy = Vector()
- for f in bpydata.tessface_uv_textures.active.data:
- fuv = f.uv
- for i, uv in enumerate(fuv):
- uv_copy.x = uv[0]
- uv_copy.y = uv[1]
-
- fuv[i] = (uv_copy * texmtx)[0:2]
- # Done transforming the texture
-
- # Must be here and not in IndexedFaceSet because it needs an object for the flip func. Messy :/
- if not ccw:
- # bpydata.flipNormals()
- # XXX25
- pass
+ geom.blendData = bpydata
- # else could be a curve for example
+ if bpydata:
+ bpyob = node.blendData = node.blendObject = bpy.data.objects.new(vrmlname, bpydata)
+ bpy.context.scene.objects.link(bpyob).select = True
- # Can transform data or object, better the object so we can instance the data
- #bpymesh.transform(getFinalMatrix(node))
- bpyob.matrix_world = getFinalMatrix(node, None, ancestry, global_matrix)
+ if bpyob:
+ # Could transform data, but better the object so we can instance the data
+ bpyob.matrix_world = getFinalMatrix(node, None, ancestry, global_matrix)
def importLamp_PointLight(node, ancestry):
@@ -2324,7 +2341,7 @@ def importLamp(node, spec, ancestry, global_matrix):
print("Error, not a lamp")
raise ValueError
- bpyob = node.blendObject = bpy.data.objects.new("TODO", bpylamp)
+ bpyob = node.blendData = node.blendObject = bpy.data.objects.new("TODO", bpylamp)
bpy.context.scene.objects.link(bpyob).select = True
bpyob.matrix_world = getFinalMatrix(node, mtx, ancestry, global_matrix)
@@ -2347,7 +2364,7 @@ def importViewpoint(node, ancestry, global_matrix):
mtx = Matrix.Translation(Vector(position)) * translateRotation(orientation)
- bpyob = node.blendObject = bpy.data.objects.new(name, bpycam)
+ bpyob = node.blendData = node.blendObject = bpy.data.objects.new(name, bpycam)
bpy.context.scene.objects.link(bpyob).select = True
bpyob.matrix_world = getFinalMatrix(node, mtx, ancestry, global_matrix)
@@ -2357,7 +2374,7 @@ def importTransform(node, ancestry, global_matrix):
if not name:
name = 'Transform'
- bpyob = node.blendObject = bpy.data.objects.new(name, None)
+ bpyob = node.blendData = node.blendObject = bpy.data.objects.new(name, None)
bpy.context.scene.objects.link(bpyob).select = True
bpyob.matrix_world = getFinalMatrix(node, None, ancestry, global_matrix)
@@ -2615,14 +2632,14 @@ def load_web3d(path,
# Assign anim curves
node = defDict[key]
- if node.blendObject is None: # Add an object if we need one for animation
- node.blendObject = bpy.data.objects.new('AnimOb', None) # , name)
+ if node.blendData is None: # Add an object if we need one for animation
+ node.blendData = node.blendObject = bpy.data.objects.new('AnimOb', None) # , name)
bpy.context.scene.objects.link(node.blendObject).select = True
- if node.blendObject.animation_data is None:
- node.blendObject.animation_data_create()
+ if node.blendData.animation_data is None:
+ node.blendData.animation_data_create()
- node.blendObject.animation_data.action = action
+ node.blendData.animation_data.action = action
# Add in hierarchy
if PREF_FLAT is False: