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>2019-03-16 14:05:30 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2019-03-16 14:09:27 +0300
commite8da70ab73d2dd5ff46e47c87cf2da633446670f (patch)
tree1917c3cf7e713cbf1c93ea0e7c561268f2277e45 /io_scene_x3d
parentd17b93756929e1b7bf5cce8a3073fa532f750e39 (diff)
X3D: basic initial port to blender2.8.
That was a rather heavy work, since in 2.7 that add-on was still using tessellated geometry API quiet extensively (and that one has been removed from 2.8)... Also updated some minor things on the road, like e.g. exporting ColorRGBA for vertex colors, since ours now have some alpha. Main remaining TODO is materials afaik (those need to be ported to the new nodeshader wrapper), not very high priority for now. Also note that the whole code has many sub-optimal handling, but that whole format is not really designed for heavy geometries anyway I think, so this is probably fine for now (and going over whole code to optimize it would be quiet a work too).
Diffstat (limited to 'io_scene_x3d')
-rw-r--r--io_scene_x3d/__init__.py22
-rw-r--r--io_scene_x3d/export_x3d.py318
-rw-r--r--io_scene_x3d/import_x3d.py654
3 files changed, 498 insertions, 496 deletions
diff --git a/io_scene_x3d/__init__.py b/io_scene_x3d/__init__.py
index 8115f72e..54377704 100644
--- a/io_scene_x3d/__init__.py
+++ b/io_scene_x3d/__init__.py
@@ -21,8 +21,8 @@
bl_info = {
"name": "Web3D X3D/VRML2 format",
"author": "Campbell Barton, Bart, Bastien Montagne, Seva Alekseyev",
- "version": (1, 2, 0),
- "blender": (2, 76, 0),
+ "version": (2, 2, 0),
+ "blender": (2, 80, 0),
"location": "File > Import-Export",
"description": "Import-Export X3D, Import VRML2",
"warning": "",
@@ -152,7 +152,7 @@ class ExportX3D(bpy.types.Operator, ExportHelper):
))
global_matrix = axis_conversion(to_forward=self.axis_forward,
to_up=self.axis_up,
- ).to_4x4() * Matrix.Scale(self.global_scale, 4)
+ ).to_4x4() @ Matrix.Scale(self.global_scale, 4)
keywords["global_matrix"] = global_matrix
return export_x3d.save(context, **keywords)
@@ -168,21 +168,27 @@ def menu_func_export(self, context):
text="X3D Extensible 3D (.x3d)")
+classes = (
+ ExportX3D,
+ ImportX3D,
+)
+
+
def register():
- bpy.utils.register_module(__name__)
+ for cls in classes:
+ bpy.utils.register_class(cls)
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
def unregister():
- bpy.utils.unregister_module(__name__)
-
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
-# NOTES
-# - blender version is hardcoded
+ for cls in classes:
+ bpy.utils.unregister_class(cls)
+
if __name__ == "__main__":
register()
diff --git a/io_scene_x3d/export_x3d.py b/io_scene_x3d/export_x3d.py
index d6c4a293..88ac5ed2 100644
--- a/io_scene_x3d/export_x3d.py
+++ b/io_scene_x3d/export_x3d.py
@@ -53,7 +53,7 @@ def clight_color(col):
def matrix_direction_neg_z(matrix):
- return (matrix.to_3x3() * mathutils.Vector((0.0, 0.0, -1.0))).normalized()[:]
+ return (matrix.to_3x3() @ mathutils.Vector((0.0, 0.0, -1.0))).normalized()[:]
def prefix_quoted_str(value, prefix):
@@ -218,6 +218,7 @@ def h3d_is_object_view(scene, obj):
def export(file,
global_matrix,
scene,
+ view_layer,
use_mesh_modifiers=False,
use_selection=True,
use_triangulate=False,
@@ -410,11 +411,11 @@ def export(file,
fw('%s</Transform>\n' % ident)
return ident
- def writeSpotLight(ident, obj, matrix, lamp, world):
+ def writeSpotLight(ident, obj, matrix, light, world):
# note, light_id is not re-used
light_id = quoteattr(unique_name(obj, LA_ + obj.name, uuid_cache_light, clean_func=clean_def, sep="_"))
- if world:
+ if world and 0:
ambi = world.ambient_color
amb_intensity = ((ambi[0] + ambi[1] + ambi[2]) / 3.0) / 2.5
del ambi
@@ -439,18 +440,18 @@ def export(file,
fw(ident_step + 'radius="%.4f"\n' % radius)
fw(ident_step + 'ambientIntensity="%.4f"\n' % amb_intensity)
fw(ident_step + 'intensity="%.4f"\n' % intensity)
- fw(ident_step + 'color="%.4f %.4f %.4f"\n' % clight_color(lamp.color))
+ fw(ident_step + 'color="%.4f %.4f %.4f"\n' % clight_color(light.color))
fw(ident_step + 'beamWidth="%.4f"\n' % beamWidth)
fw(ident_step + 'cutOffAngle="%.4f"\n' % cutOffAngle)
fw(ident_step + 'direction="%.4f %.4f %.4f"\n' % orientation)
fw(ident_step + 'location="%.4f %.4f %.4f"\n' % location)
fw(ident_step + '/>\n')
- def writeDirectionalLight(ident, obj, matrix, lamp, world):
+ def writeDirectionalLight(ident, obj, matrix, light, world):
# note, light_id is not re-used
light_id = quoteattr(unique_name(obj, LA_ + obj.name, uuid_cache_light, clean_func=clean_def, sep="_"))
- if world:
+ if world and 0:
ambi = world.ambient_color
# ambi = world.amb
amb_intensity = ((float(ambi[0] + ambi[1] + ambi[2])) / 3.0) / 2.5
@@ -458,7 +459,7 @@ def export(file,
ambi = 0
amb_intensity = 0.0
- intensity = min(lamp.energy / 1.75, 1.0)
+ intensity = min(light.energy / 1.75, 1.0)
orientation = matrix_direction_neg_z(matrix)
@@ -466,16 +467,16 @@ def export(file,
fw('%s<DirectionalLight ' % ident)))
fw('DEF=%s\n' % light_id)
fw(ident_step + 'ambientIntensity="%.4f"\n' % amb_intensity)
- fw(ident_step + 'color="%.4f %.4f %.4f"\n' % clight_color(lamp.color))
+ fw(ident_step + 'color="%.4f %.4f %.4f"\n' % clight_color(light.color))
fw(ident_step + 'intensity="%.4f"\n' % intensity)
fw(ident_step + 'direction="%.4f %.4f %.4f"\n' % orientation)
fw(ident_step + '/>\n')
- def writePointLight(ident, obj, matrix, lamp, world):
+ def writePointLight(ident, obj, matrix, light, world):
# note, light_id is not re-used
light_id = quoteattr(unique_name(obj, LA_ + obj.name, uuid_cache_light, clean_func=clean_def, sep="_"))
- if world:
+ if world and 0:
ambi = world.ambient_color
# ambi = world.amb
amb_intensity = ((float(ambi[0] + ambi[1] + ambi[2])) / 3.0) / 2.5
@@ -483,17 +484,17 @@ def export(file,
ambi = 0.0
amb_intensity = 0.0
- intensity = min(lamp.energy / 1.75, 1.0)
+ intensity = min(light.energy / 1.75, 1.0)
location = matrix.to_translation()[:]
ident_step = ident + (' ' * (-len(ident) + \
fw('%s<PointLight ' % ident)))
fw('DEF=%s\n' % light_id)
fw(ident_step + 'ambientIntensity="%.4f"\n' % amb_intensity)
- fw(ident_step + 'color="%.4f %.4f %.4f"\n' % clight_color(lamp.color))
+ fw(ident_step + 'color="%.4f %.4f %.4f"\n' % clight_color(light.color))
fw(ident_step + 'intensity="%.4f"\n' % intensity)
- fw(ident_step + 'radius="%.4f" \n' % lamp.distance)
+ fw(ident_step + 'radius="%.4f" \n' % light.distance)
fw(ident_step + 'location="%.4f %.4f %.4f"\n' % location)
fw(ident_step + '/>\n')
@@ -504,12 +505,10 @@ def export(file,
mesh_id_coords = prefix_quoted_str(mesh_id, 'coords_')
mesh_id_normals = prefix_quoted_str(mesh_id, 'normals_')
- # tessellation faces may not exist
- if not mesh.tessfaces and mesh.polygons:
- mesh.update(calc_tessface=True)
-
- if not mesh.tessfaces:
- return
+ # Be sure tessellated loop triangles are available!
+ if use_triangulate:
+ if not mesh.loop_triangles and mesh.polygons:
+ mesh.calc_loop_triangles()
use_collnode = bool([mod for mod in obj.modifiers
if mod.type == 'COLLISION'
@@ -531,7 +530,7 @@ def export(file,
fw('%s<Group DEF=%s>\n' % (ident, mesh_id_group))
ident += '\t'
- is_uv = bool(mesh.tessface_uv_textures.active)
+ is_uv = bool(mesh.uv_layers.active)
# is_col, defined for each material
is_coords_written = False
@@ -545,7 +544,7 @@ def export(file,
mesh_material_images = [None] * len(mesh_materials)
for i, material in enumerate(mesh_materials):
- if material:
+ if 0 and material:
for mtex in material.texture_slots:
if mtex:
tex = mtex.texture
@@ -557,44 +556,34 @@ def export(file,
mesh_material_images[i] = image
break
- mesh_materials_use_face_texture = [getattr(material, 'use_face_texture', True) for material in mesh_materials]
-
# fast access!
mesh_vertices = mesh.vertices[:]
- mesh_faces = mesh.tessfaces[:]
- mesh_faces_materials = [f.material_index for f in mesh_faces]
- mesh_faces_vertices = [f.vertices[:] for f in mesh_faces]
-
- if is_uv and True in mesh_materials_use_face_texture:
- mesh_faces_image = [(fuv.image
- if mesh_materials_use_face_texture[mesh_faces_materials[i]]
- else mesh_material_images[mesh_faces_materials[i]])
- for i, fuv in enumerate(mesh.tessface_uv_textures.active.data)]
-
- mesh_faces_image_unique = set(mesh_faces_image)
- elif len(set(mesh_material_images) | {None}) > 1: # make sure there is at least one image
- mesh_faces_image = [mesh_material_images[material_index] for material_index in mesh_faces_materials]
- mesh_faces_image_unique = set(mesh_faces_image)
+ mesh_loops = mesh.loops[:]
+ mesh_polygons = mesh.polygons[:]
+ mesh_polygons_materials = [p.material_index for p in mesh_polygons]
+ mesh_polygons_vertices = [p.vertices[:] for p in mesh_polygons]
+
+ if len(set(mesh_material_images)) > 0: # make sure there is at least one image
+ mesh_polygons_image = [mesh_material_images[material_index] for material_index in mesh_polygons_materials]
else:
- mesh_faces_image = [None] * len(mesh_faces)
- mesh_faces_image_unique = {None}
+ mesh_polygons_image = [None] * len(mesh_polygons)
+ mesh_polygons_image_unique = set(mesh_polygons_image)
# group faces
- face_groups = {}
+ polygons_groups = {}
for material_index in range(len(mesh_materials)):
- for image in mesh_faces_image_unique:
- face_groups[material_index, image] = []
- del mesh_faces_image_unique
+ for image in mesh_polygons_image_unique:
+ polygons_groups[material_index, image] = []
+ del mesh_polygons_image_unique
- for i, (material_index, image) in enumerate(zip(mesh_faces_materials, mesh_faces_image)):
- face_groups[material_index, image].append(i)
+ for i, (material_index, image) in enumerate(zip(mesh_polygons_materials, mesh_polygons_image)):
+ polygons_groups[material_index, image].append(i)
- # same as face_groups.items() but sorted so we can get predictable output.
- face_groups_items = list(face_groups.items())
- face_groups_items.sort(key=lambda m: (m[0][0], getattr(m[0][1], 'name', '')))
+ # Py dict are sorted now, so we can use directly polygons_groups.items()
+ # and still get consistent reproducible outputs.
- is_col = (mesh.tessface_vertex_colors.active and (material is None or material.use_vertex_color_paint))
- mesh_faces_col = mesh.tessface_vertex_colors.active.data if is_col else None
+ is_col = (mesh.vertex_colors.active and (material is None or material.use_vertex_color_paint))
+ mesh_loops_col = mesh.vertex_colors.active.data if is_col else None
# Check if vertex colors can be exported in per-vertex mode.
# Do we have just one color per vertex in every face that uses the vertex?
@@ -602,13 +591,12 @@ def export(file,
def calc_vertex_color():
vert_color = [None] * len(mesh.vertices)
- for i, face in enumerate(mesh_faces):
- fcol = mesh_faces_col[i]
- face_colors = (fcol.color1, fcol.color2, fcol.color3, fcol.color4)
- for j, vert_index in enumerate(face.vertices):
- if vert_color[vert_index] is None:
- vert_color[vert_index] = face_colors[j][:]
- elif vert_color[vert_index] != face_colors[j][:]:
+ for i, p in enumerate(mesh_polygons):
+ for lidx in p.loop_indices:
+ l = mesh_loops[lidx]
+ if vert_color[l.vertex_index] is None:
+ vert_color[l.vertex_index] = mesh_loops_col[lidx].color[:]
+ elif vert_color[l.vertex_index] != mesh_loops_col[lidx].color[:]:
return False, ()
return True, vert_color
@@ -616,8 +604,14 @@ def export(file,
is_col_per_vertex, vert_color = calc_vertex_color()
del calc_vertex_color
- for (material_index, image), face_group in face_groups_items: # face_groups.items()
- if face_group:
+ # If using looptris, we need a mapping poly_index -> loop_tris_indices...
+ if use_triangulate:
+ polygons_to_loop_triangles_indices = [[] for i in range(len(mesh_polygons))]
+ for ltri in mesh.loop_triangles:
+ polygons_to_loop_triangles_indices[ltri.polygon_index].append(ltri)
+
+ for (material_index, image), polygons_group in polygons_groups.items():
+ if polygons_group:
material = mesh_materials[material_index]
fw('%s<Shape>\n' % ident)
@@ -626,8 +620,8 @@ def export(file,
is_smooth = False
# kludge but as good as it gets!
- for i in face_group:
- if mesh_faces[i].use_smooth:
+ for i in polygons_group:
+ if mesh_polygons[i].use_smooth:
is_smooth = True
break
@@ -659,34 +653,30 @@ def export(file,
if image and not use_h3d:
writeImageTexture(ident, image)
- if mesh_materials_use_face_texture[material_index]:
- if image.use_tiles:
- fw('%s<TextureTransform scale="%s %s" />\n' % (ident, image.tiles_x, image.tiles_y))
- else:
- # transform by mtex
- loc = mesh_material_mtex[material_index].offset[:2]
+ # transform by mtex
+ loc = mesh_material_mtex[material_index].offset[:2]
- # mtex_scale * tex_repeat
- sca_x, sca_y = mesh_material_mtex[material_index].scale[:2]
+ # mtex_scale * tex_repeat
+ sca_x, sca_y = mesh_material_mtex[material_index].scale[:2]
- sca_x *= mesh_material_tex[material_index].repeat_x
- sca_y *= mesh_material_tex[material_index].repeat_y
+ sca_x *= mesh_material_tex[material_index].repeat_x
+ sca_y *= mesh_material_tex[material_index].repeat_y
- # flip x/y is a sampling feature, convert to transform
- if mesh_material_tex[material_index].use_flip_axis:
- rot = math.pi / -2.0
- sca_x, sca_y = sca_y, -sca_x
- else:
- rot = 0.0
+ # flip x/y is a sampling feature, convert to transform
+ if mesh_material_tex[material_index].use_flip_axis:
+ rot = math.pi / -2.0
+ sca_x, sca_y = sca_y, -sca_x
+ else:
+ rot = 0.0
- ident_step = ident + (' ' * (-len(ident) + \
- fw('%s<TextureTransform ' % ident)))
- fw('\n')
- # fw('center="%.6f %.6f" ' % (0.0, 0.0))
- fw(ident_step + 'translation="%.6f %.6f"\n' % loc)
- fw(ident_step + 'scale="%.6f %.6f"\n' % (sca_x, sca_y))
- fw(ident_step + 'rotation="%.6f"\n' % rot)
- fw(ident_step + '/>\n')
+ ident_step = ident + (' ' * (-len(ident) + \
+ fw('%s<TextureTransform ' % ident)))
+ fw('\n')
+ # fw('center="%.6f %.6f" ' % (0.0, 0.0))
+ fw(ident_step + 'translation="%.6f %.6f"\n' % loc)
+ fw(ident_step + 'scale="%.6f %.6f"\n' % (sca_x, sca_y))
+ fw(ident_step + 'rotation="%.6f"\n' % rot)
+ fw(ident_step + '/>\n')
if use_h3d:
mat_tmp = material if material else gpu_shader_dummy_mat
@@ -700,7 +690,7 @@ def export(file,
ident = ident[:-1]
fw('%s</Appearance>\n' % ident)
- mesh_faces_uv = mesh.tessface_uv_textures.active.data if is_uv else None
+ mesh_loops_uv = mesh.uv_layers.active.data if is_uv else None
#-- IndexedFaceSet or IndexedLineSet
if use_triangulate:
@@ -708,7 +698,7 @@ def export(file,
fw('%s<IndexedTriangleSet ' % ident)))
# --- Write IndexedTriangleSet Attributes (same as IndexedFaceSet)
- fw('solid="%s"\n' % bool_as_str(material and material.game_settings.use_backface_culling))
+ fw('solid="false"\n') # not available anymore: bool_as_str(material and material.game_settings.use_backface_culling))
if use_normals or is_force_normals:
fw(ident_step + 'normalPerVertex="true"\n')
@@ -723,67 +713,58 @@ def export(file,
slot_uv = 0
slot_col = 1
- def vertex_key(fidx, f_cnr_idx):
+ def vertex_key(lidx):
return (
- mesh_faces_uv[fidx].uv[f_cnr_idx][:],
- getattr(mesh_faces_col[fidx], "color%d" % (f_cnr_idx + 1))[:],
+ mesh_loops_uv[lidx].uv[:],
+ mesh_loops_col[lidx].color[:],
)
elif is_uv:
slot_uv = 0
- def vertex_key(fidx, f_cnr_idx):
+ def vertex_key(lidx):
return (
- mesh_faces_uv[fidx].uv[f_cnr_idx][:],
+ mesh_loops_uv[lidx].uv[:],
)
elif is_col:
slot_col = 0
- def vertex_key(fidx, f_cnr_idx):
+ def vertex_key(lidx):
return (
- getattr(mesh_faces_col[fidx], "color%d" % (f_cnr_idx + 1))[:],
+ mesh_loops_col[lidx].color[:],
)
else:
# ack, not especially efficient in this case
- def vertex_key(fidx, f_cnr_idx):
+ def vertex_key(lidx):
return None
# build a mesh mapping dict
vertex_hash = [{} for i in range(len(mesh.vertices))]
# worst case every face is a quad
- face_tri_list = [[None, None, None] for i in range(len(mesh.tessfaces) * 2)]
+ face_tri_list = [[None, None, None] for i in range(len(mesh.loop_triangles))]
vert_tri_list = []
totvert = 0
totface = 0
- temp_face = [None] * 4
- for i in face_group:
- fv = mesh_faces_vertices[i]
- for j, v_idx in enumerate(fv):
- key = vertex_key(i, j)
- vh = vertex_hash[v_idx]
- x3d_v = vh.get(key)
- if x3d_v is None:
- x3d_v = key, v_idx, totvert
- vh[key] = x3d_v
- # key / original_vertex / new_vertex
- vert_tri_list.append(x3d_v)
- totvert += 1
- temp_face[j] = x3d_v
-
- if len(fv) == 4:
- f_iter = ((0, 1, 2), (0, 2, 3))
- else:
- f_iter = ((0, 1, 2), )
-
- for f_it in f_iter:
- # loop over a quad as 2 tris
- f_tri = face_tri_list[totface]
- for ji, j in enumerate(f_it):
- f_tri[ji] = temp_face[j]
- # quads run this twice
+ temp_tri = [None] * 3
+ for pidx in polygons_group:
+ for ltri in polygons_to_loop_triangles_indices[pidx]:
+ print(pidx, ltri.vertices[:])
+ for tri_vidx, (lidx, vidx) in enumerate(zip(ltri.loops, ltri.vertices)):
+ key = vertex_key(lidx)
+ vh = vertex_hash[vidx]
+ x3d_v = vh.get(key)
+ if x3d_v is None:
+ x3d_v = key, vidx, totvert
+ vh[key] = x3d_v
+ # key / original_vertex / new_vertex
+ vert_tri_list.append(x3d_v)
+ totvert += 1
+ temp_tri[tri_vidx] = x3d_v
+ print(temp_tri)
+
+ face_tri_list[totface][:] = temp_tri[:]
totface += 1
- # clear unused faces
- face_tri_list[totface:] = []
+ assert(len(face_tri_list) == len(mesh.loop_triangles))
fw(ident_step + 'index="')
for x3d_f in face_tri_list:
@@ -814,9 +795,9 @@ def export(file,
fw('" />\n')
if is_col:
- fw('%s<Color color="' % ident)
+ fw('%s<ColorRGBA color="' % ident)
for x3d_v in vert_tri_list:
- fw('%.3f %.3f %.3f ' % x3d_v[0][slot_col])
+ fw('%.3f %.3f %.3f %.3f ' % x3d_v[0][slot_col])
fw('" />\n')
if use_h3d:
@@ -851,7 +832,7 @@ def export(file,
fw('%s<IndexedFaceSet ' % ident)))
# --- Write IndexedFaceSet Attributes (same as IndexedTriangleSet)
- fw('solid="%s"\n' % bool_as_str(material and material.game_settings.use_backface_culling))
+ fw('solid="false"\n') # not available anymore: bool_as_str(material and material.game_settings.use_backface_culling)
if is_smooth:
# use Auto-Smooth angle, if enabled. Otherwise make
# the mesh perfectly smooth by creaseAngle > pi.
@@ -865,29 +846,23 @@ def export(file,
if is_col and not is_col_per_vertex:
fw(ident_step + 'colorPerVertex="false"\n')
- # for IndexedTriangleSet we use a uv per vertex so this isnt needed.
+ # for IndexedTriangleSet we use a uv per vertex so this isn't needed.
if is_uv:
fw(ident_step + 'texCoordIndex="')
j = 0
- for i in face_group:
- if len(mesh_faces_vertices[i]) == 4:
- fw('%d %d %d %d -1 ' % (j, j + 1, j + 2, j + 3))
- j += 4
- else:
- fw('%d %d %d -1 ' % (j, j + 1, j + 2))
- j += 3
+ for i in polygons_group:
+ num_poly_verts = len(mesh_polygons_vertices[i])
+ fw('%s -1 ' % ' '.join((str(i) for i in range(j, j + num_poly_verts))))
+ j += num_poly_verts
fw('"\n')
# --- end texCoordIndex
if True:
fw(ident_step + 'coordIndex="')
- for i in face_group:
- fv = mesh_faces_vertices[i]
- if len(fv) == 3:
- fw('%i %i %i -1 ' % fv)
- else:
- fw('%i %i %i %i -1 ' % fv)
+ for i in polygons_group:
+ poly_verts = mesh_polygons_vertices[i]
+ fw('%s -1 ' % ' '.join((str(i) for i in poly_verts)))
fw('"\n')
# --- end coordIndex
@@ -926,25 +901,24 @@ def export(file,
if is_uv:
fw('%s<TextureCoordinate point="' % ident)
- for i in face_group:
- for uv in mesh_faces_uv[i].uv:
- fw('%.4f %.4f ' % uv[:])
- del mesh_faces_uv
+ for i in polygons_group:
+ for lidx in mesh_polygons[i].loop_indices:
+ fw('%.4f %.4f ' % mesh_loops_uv[lidx].uv[:])
fw('" />\n')
if is_col:
# Need better logic here, dynamic determination
# which of the X3D coloring models fits better this mesh - per face
# or per vertex. Probably with an explicit fallback mode parameter.
- fw('%s<Color color="' % ident)
+ fw('%s<ColorRGBA color="' % ident)
if is_col_per_vertex:
for i in range(len(mesh.vertices)):
# may be None,
- fw('%.3f %.3f %.3f ' % (vert_color[i] or (0.0, 0.0, 0.0)))
+ fw('%.3f %.3f %.3f %.3f ' % (vert_color[i] or (0.0, 0.0, 0.0, 0.0)))
else: # Export as colors per face.
# TODO: average them rather than using the first one!
- for i in face_group:
- fw('%.3f %.3f %.3f ' % mesh_faces_col[i].color1[:])
+ for i in polygons_group:
+ fw('%.3f %.3f %.3f %.3f ' % mesh_loops_col[mesh_polygons[i].loop_start].color[:])
fw('" />\n')
#--- output vertexColors
@@ -981,23 +955,23 @@ def export(file,
else:
material.tag = True
- emit = material.emit
- ambient = material.ambient / 3.0
- diffuseColor = material.diffuse_color[:]
- if world:
+ emit = 0.0 #material.emit
+ ambient = 0.0 #material.ambient / 3.0
+ diffuseColor = material.diffuse_color[:3]
+ if world and 0:
ambiColor = ((material.ambient * 2.0) * world.ambient_color)[:]
else:
ambiColor = 0.0, 0.0, 0.0
emitColor = tuple(((c * emit) + ambiColor[i]) / 2.0 for i, c in enumerate(diffuseColor))
- shininess = material.specular_hardness / 512.0
+ shininess = material.specular_intensity
specColor = tuple((c + 0.001) / (1.25 / (material.specular_intensity + 0.001)) for c in material.specular_color)
- transp = 1.0 - material.alpha
+ transp = 1.0 - material.diffuse_color[3]
- if material.use_shadeless:
- ambient = 1.0
- shininess = 0.0
- specColor = emitColor = diffuseColor
+ # ~ if material.use_shadeless:
+ # ~ ambient = 1.0
+ # ~ shininess = 0.0
+ # ~ specColor = emitColor = diffuseColor
ident_step = ident + (' ' * (-len(ident) + \
fw('%s<Material ' % ident)))
@@ -1328,10 +1302,17 @@ def export(file,
# note, not re-used
world_id = quoteattr(unique_name(world, WO_ + world.name, uuid_cache_world, clean_func=clean_def, sep="_"))
- blending = world.use_sky_blend, world.use_sky_paper, world.use_sky_real
+ # XXX World changed a lot in 2.8... For now do minimal get-it-to-work job.
+ # ~ blending = world.use_sky_blend, world.use_sky_paper, world.use_sky_real
+
+ # ~ grd_triple = clight_color(world.horizon_color)
+ # ~ sky_triple = clight_color(world.zenith_color)
+ # ~ mix_triple = clight_color((grd_triple[i] + sky_triple[i]) / 2.0 for i in range(3))
+
+ blending = (False, False, False)
- grd_triple = clight_color(world.horizon_color)
- sky_triple = clight_color(world.zenith_color)
+ grd_triple = clight_color(world.color)
+ sky_triple = clight_color(world.color)
mix_triple = clight_color((grd_triple[i] + sky_triple[i]) / 2.0 for i in range(3))
ident_step = ident + (' ' * (-len(ident) + \
@@ -1400,14 +1381,14 @@ def export(file,
if use_hierarchy:
obj_main_matrix_world = obj_main.matrix_world
if obj_main_parent:
- obj_main_matrix = obj_main_parent.matrix_world.inverted(matrix_fallback) * obj_main_matrix_world
+ obj_main_matrix = obj_main_parent.matrix_world.inverted(matrix_fallback) @ obj_main_matrix_world
else:
obj_main_matrix = obj_main_matrix_world
obj_main_matrix_world_invert = obj_main_matrix_world.inverted(matrix_fallback)
obj_main_id = quoteattr(unique_name(obj_main, obj_main.name, uuid_cache_object, clean_func=clean_def, sep="_"))
- ident = writeTransform_begin(ident, obj_main_matrix if obj_main_parent else global_matrix * obj_main_matrix, suffix_quoted_str(obj_main_id, _TRANSFORM))
+ ident = writeTransform_begin(ident, obj_main_matrix if obj_main_parent else global_matrix @ obj_main_matrix, suffix_quoted_str(obj_main_id, _TRANSFORM))
# Set here just incase we dont enter the loop below.
is_dummy_tx = False
@@ -1417,9 +1398,9 @@ def export(file,
if use_hierarchy:
# make transform node relative
- obj_matrix = obj_main_matrix_world_invert * obj_matrix
+ obj_matrix = obj_main_matrix_world_invert @ obj_matrix
else:
- obj_matrix = global_matrix * obj_matrix
+ obj_matrix = global_matrix @ obj_matrix
# H3D - use for writing a dummy transform parent
is_dummy_tx = False
@@ -1513,9 +1494,9 @@ def export(file,
bpy.data.images.tag(False)
if use_selection:
- objects = [obj for obj in scene.objects if obj.is_visible(scene) and obj.select]
+ objects = [obj for obj in scene.objects if obj.visible_get(view_layer=view_layer) and obj.select]
else:
- objects = [obj for obj in scene.objects if obj.is_visible(scene)]
+ objects = [obj for obj in scene.objects if obj.visible_get(view_layer=view_layer)]
print('Info: starting X3D export to %r...' % file.name)
ident = ''
@@ -1607,6 +1588,7 @@ def save(context,
export(file,
global_matrix,
context.scene,
+ context.view_layer,
use_mesh_modifiers=use_mesh_modifiers,
use_selection=use_selection,
use_triangulate=use_triangulate,
diff --git a/io_scene_x3d/import_x3d.py b/io_scene_x3d/import_x3d.py
index efcbb64e..917cf83d 100644
--- a/io_scene_x3d/import_x3d.py
+++ b/io_scene_x3d/import_x3d.py
@@ -25,6 +25,7 @@ import os
import shlex
import math
from math import sin, cos, pi
+from itertools import chain
texture_cache = {}
material_cache = {}
@@ -1537,7 +1538,7 @@ def translateTransform(node, ancestry):
mats = [tx_mat, cent_mat, rot_mat, scaori_mat, sca_mat, scaori_imat, cent_imat]
for mtx in mats:
if mtx:
- new_mat = new_mat * mtx
+ new_mat = new_mat @ mtx
return new_mat
@@ -1577,7 +1578,7 @@ def translateTexTransform(node, ancestry):
for mtx in mats:
if mtx:
- new_mat = new_mat * mtx
+ new_mat = new_mat @ mtx
return new_mat
@@ -1593,10 +1594,10 @@ def getFinalMatrix(node, mtx, ancestry, global_matrix):
for node_tx in transform_nodes:
mat = translateTransform(node_tx, ancestry)
- mtx = mat * mtx
+ mtx = mat @ mtx
# worldspace matrix
- mtx = global_matrix * mtx
+ mtx = global_matrix @ mtx
return mtx
@@ -1604,38 +1605,34 @@ def getFinalMatrix(node, mtx, ancestry, global_matrix):
# -----------------------------------------------------------------------------------
# Mesh import utilities
-# Assumes that the mesh has tessfaces - doesn't support polygons.
-# Also assumes that tessfaces are all triangles.
-# Assumes that the sequence of the mesh vertices array matches
-# the source file. For indexed meshes, that's almost a given;
-# for nonindexed ones, this is a consideration.
-
-
+# Assumes that the mesh has polygons.
def importMesh_ApplyColors(bpymesh, geom, ancestry):
colors = geom.getChildBySpec(['ColorRGBA', 'Color'])
if colors:
if colors.getSpec() == 'ColorRGBA':
+ rgb = colors.getFieldAsArray('color', 4, ancestry)
+ else:
# Array of arrays; no need to flatten
- rgb = [c[:3] for c
- in colors.getFieldAsArray('color', 4, ancestry)]
+ rgb = [c + [1.0] for c in colors.getFieldAsArray('color', 3, ancestry)]
+ lcol_layer = bpymesh.vertex_colors.new()
+
+ if len(rgb) == len(bpymesh.vertices):
+ rgb = [rgb[l.vertex_index] for l in bpymesh.loops]
+ rgb = tuple(chain(*rgb))
+ elif len(rgb) == len(bpymesh.loops):
+ rgb = tuple(chain(*rgb))
else:
- rgb = colors.getFieldAsArray('color', 3, ancestry)
- tc = bpymesh.tessface_vertex_colors.new()
- tc.data.foreach_set("color1", [i for face
- in bpymesh.tessfaces
- for i in rgb[face.vertices[0]]])
- tc.data.foreach_set("color2", [i for face
- in bpymesh.tessfaces
- for i in rgb[face.vertices[1]]])
- tc.data.foreach_set("color3", [i for face
- in bpymesh.tessfaces
- for i in rgb[face.vertices[2]]])
+ printf("WARNING not applying vertex colors, non matching numbers of vertices or loops (%d vs %d/%d)"
+ "" % (len(rgb), len(bpymesh.vertices), len(bpymesh.loops)))
+ return
+
+ lcol_layer.data.foreach_set("color", rgb)
# Assumes that the vertices have not been rearranged compared to the
# source file order # or in the order assumed by the spec (e. g. in
# Elevation, in rows by x).
-# Assumes tessfaces have been set, doesn't support polygons.
+# Assumes polygons have been set.
def importMesh_ApplyNormals(bpymesh, geom, ancestry):
normals = geom.getChildBySpec('Normal')
if not normals:
@@ -1646,14 +1643,14 @@ def importMesh_ApplyNormals(bpymesh, geom, ancestry):
if per_vertex:
bpymesh.vertices.foreach_set("normal", vectors)
else:
- bpymesh.tessfaces.foreach_set("normal", vectors)
+ bpymesh.polygons.foreach_set("normal", vectors)
# Reads the standard Coordinate object - common for all mesh elements
# Feeds the vertices in the mesh.
# Rearranging the vertex order is a bad idea - other elements
# in X3D might rely on it, if you need to rearrange, please play with
-# vertex indices in the tessfaces/polygons instead.
+# vertex indices in the polygons instead.
#
# Vertex culling that we have in IndexedFaceSet is an unfortunate exception,
# brought forth by a very specific issue.
@@ -1667,39 +1664,34 @@ def importMesh_ReadVertices(bpymesh, geom, ancestry):
bpymesh.vertices.foreach_set("co", points)
-# Assumes the mesh only contains triangular tessfaces, and the order
-# of vertices matches the source file.
+# Assumes that the order of vertices matches the source file.
# Relies upon texture coordinates in the X3D node; if a coordinate generation
# algorithm for a geometry is in the spec (e. g. for ElevationGrid), it needs
# to be implemented by the geometry handler.
#
# Texture transform is applied in ProcessObject.
-def importMesh_ApplyTextureToTessfaces(bpymesh, geom, ancestry, bpyima):
- if not bpyima:
- return
-
+def importMesh_ApplyUVs(bpymesh, geom, ancestry):
tex_coord = geom.getChildBySpec('TextureCoordinate')
if not tex_coord:
return
- coord_points = tex_coord.getFieldAsArray('point', 2, ancestry)
- if not coord_points:
+ uvs = tex_coord.getFieldAsArray('point', 2, ancestry)
+ if not uvs:
return
- d = bpymesh.tessface_uv_textures.new().data
- for face in d: # No foreach_set for nonscalars
- face.image = bpyima
- uv = [i for face in bpymesh.tessfaces
- for vno in range(3) for i in coord_points[face.vertices[vno]]]
- d.foreach_set('uv', uv)
+ d = bpymesh.uv_layers.new().data
+ uvs = [i for poly in bpymesh.polygons
+ for vidx in poly.vertices
+ for i in uvs[vidx]]
+ d.foreach_set('uv', uvs)
# Common steps for all triangle meshes once the geometry has been set:
-# normals, vertex colors, and texture.
-def importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry, bpyima):
+# normals, vertex colors, and UVs.
+def importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry):
importMesh_ApplyNormals(bpymesh, geom, ancestry)
importMesh_ApplyColors(bpymesh, geom, ancestry)
- importMesh_ApplyTextureToTessfaces(bpymesh, geom, ancestry, bpyima)
+ importMesh_ApplyUVs(bpymesh, geom, ancestry)
bpymesh.validate()
bpymesh.update()
return bpymesh
@@ -1708,11 +1700,9 @@ def importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry, bpyima):
# Assumes that the mesh is stored as polygons and loops, and the premade array
# of texture coordinates follows the loop array.
# The loops array must be flat.
-def importMesh_ApplyTextureToLoops(bpymesh, bpyima, loops):
- d = bpymesh.uv_textures.new().data
- for f in d:
- f.image = bpyima
- bpymesh.uv_layers[0].data.foreach_set('uv', loops)
+def importMesh_ApplyTextureToLoops(bpymesh, loops):
+ d = bpymesh.uv_layers.new().data
+ d.foreach_set('uv', loops)
def flip(r, ccw):
@@ -1722,7 +1712,7 @@ def flip(r, ccw):
# Now specific geometry importers
-def importMesh_IndexedTriangleSet(geom, ancestry, bpyima):
+def importMesh_IndexedTriangleSet(geom, ancestry):
# Ignoring solid
# colorPerVertex is always true
ccw = geom.getFieldAsBool('ccw', True, ancestry)
@@ -1732,16 +1722,20 @@ def importMesh_IndexedTriangleSet(geom, ancestry, bpyima):
# Read the faces
index = geom.getFieldAsArray('index', 0, ancestry)
- n = len(index) // 3
+ num_polys = len(index) // 3
if not ccw:
- index = [index[3 * i + j] for i in range(n) for j in (1, 0, 2)]
- bpymesh.tessfaces.add(n)
- bpymesh.tessfaces.foreach_set("vertices", index)
+ index = [index[3 * i + j] for i in range(num_polys) for j in (1, 0, 2)]
- return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry, bpyima)
+ bpymesh.loops.add(num_polys * 3)
+ bpymesh.polygons.add(num_polys)
+ bpymesh.polygons.foreach_set("loop_start", range(0, num_polys * 3, 3))
+ bpymesh.polygons.foreach_set("loop_total", (3,) * num_polys)
+ bpymesh.polygons.foreach_set("vertices", index)
+ return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry)
-def importMesh_IndexedTriangleStripSet(geom, ancestry, bpyima):
+
+def importMesh_IndexedTriangleStripSet(geom, ancestry):
# Ignoring solid
# colorPerVertex is always true
cw = 0 if geom.getFieldAsBool('ccw', True, ancestry) else 1
@@ -1753,7 +1747,11 @@ def importMesh_IndexedTriangleStripSet(geom, ancestry, bpyima):
while index[-1] == -1:
del index[-1]
ngaps = sum(1 for i in index if i == -1)
- bpymesh.tessfaces.add(len(index) - 2 - 3 * ngaps)
+ num_polys = len(index) - 2 - 3 * ngaps
+ bpymesh.loops.add(num_polys * 3)
+ bpymesh.polygons.add(num_polys)
+ bpymesh.polygons.foreach_set("loop_start", range(0, num_polys * 3, 3))
+ bpymesh.polygons.foreach_set("loop_total", (3,) * num_polys)
def triangles():
i = 0
@@ -1769,11 +1767,11 @@ def importMesh_IndexedTriangleStripSet(geom, ancestry, bpyima):
if index[i + 2] == -1:
i += 3
odd = cw
- bpymesh.tessfaces.foreach_set("vertices", [f for f in triangles()])
- return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry, bpyima)
+ bpymesh.polygons.foreach_set("vertices", [f for f in triangles()])
+ return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry)
-def importMesh_IndexedTriangleFanSet(geom, ancestry, bpyima):
+def importMesh_IndexedTriangleFanSet(geom, ancestry):
# Ignoring solid
# colorPerVertex is always true
cw = 0 if geom.getFieldAsBool('ccw', True, ancestry) else 1
@@ -1785,7 +1783,11 @@ def importMesh_IndexedTriangleFanSet(geom, ancestry, bpyima):
while index[-1] == -1:
del index[-1]
ngaps = sum(1 for i in index if i == -1)
- bpymesh.tessfaces.add(len(index) - 2 - 3 * ngaps)
+ num_polys = len(index) - 2 - 3 * ngaps
+ bpymesh.loops.add(num_polys * 3)
+ bpymesh.polygons.add(num_polys)
+ bpymesh.polygons.foreach_set("loop_start", range(0, num_polys * 3, 3))
+ bpymesh.polygons.foreach_set("loop_total", (3,) * num_polys)
def triangles():
i = 0
@@ -1800,35 +1802,44 @@ def importMesh_IndexedTriangleFanSet(geom, ancestry, bpyima):
if index[i + j + 1] == -1:
i = j + 2
j = 1
- bpymesh.tessfaces.foreach_set("vertices", [f for f in triangles()])
- return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry, bpyima)
+ bpymesh.polygons.foreach_set("vertices", [f for f in triangles()])
+ return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry)
-def importMesh_TriangleSet(geom, ancestry, bpyima):
+def importMesh_TriangleSet(geom, ancestry):
# Ignoring solid
# colorPerVertex is always true
ccw = geom.getFieldAsBool('ccw', True, ancestry)
bpymesh = bpy.data.meshes.new(name="TriangleSet")
importMesh_ReadVertices(bpymesh, geom, ancestry)
n = len(bpymesh.vertices)
- bpymesh.tessfaces.add(n // 3)
+ num_polys = n // 3
+ bpymesh.loops.add(num_polys * 3)
+ bpymesh.polygons.add(num_polys)
+ bpymesh.polygons.foreach_set("loop_start", range(0, num_polys * 3, 3))
+ bpymesh.polygons.foreach_set("loop_total", (3,) * num_polys)
+
if ccw:
fv = [i for i in range(n)]
else:
fv = [3 * i + j for i in range(n // 3) for j in (1, 0, 2)]
- bpymesh.tessfaces.foreach_set("vertices", fv)
+ bpymesh.polygons.foreach_set("vertices", fv)
- return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry, bpyima)
+ return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry)
-def importMesh_TriangleStripSet(geom, ancestry, bpyima):
+def importMesh_TriangleStripSet(geom, ancestry):
# Ignoring solid
# colorPerVertex is always true
cw = 0 if geom.getFieldAsBool('ccw', True, ancestry) else 1
bpymesh = bpy.data.meshes.new(name="TriangleStripSet")
importMesh_ReadVertices(bpymesh, geom, ancestry)
counts = geom.getFieldAsArray('stripCount', 0, ancestry)
- bpymesh.tessfaces.add(sum([n - 2 for n in counts]))
+ num_polys = sum([n - 2 for n in counts])
+ bpymesh.loops.add(num_polys * 3)
+ bpymesh.polygons.add(num_polys)
+ bpymesh.polygons.foreach_set("loop_start", range(0, num_polys * 3, 3))
+ bpymesh.polygons.foreach_set("loop_total", (3,) * num_polys)
def triangles():
b = 0
@@ -1838,19 +1849,23 @@ def importMesh_TriangleStripSet(geom, ancestry, bpyima):
yield b + j + 1 - (j + cw) % 2
yield b + j + 2
b += counts[i]
- bpymesh.tessfaces.foreach_set("vertices", [x for x in triangles()])
+ bpymesh.polygons.foreach_set("vertices", [x for x in triangles()])
- return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry, bpyima)
+ return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry)
-def importMesh_TriangleFanSet(geom, ancestry, bpyima):
+def importMesh_TriangleFanSet(geom, ancestry):
# Ignoring solid
# colorPerVertex is always true
cw = 0 if geom.getFieldAsBool('ccw', True, ancestry) else 1
bpymesh = bpy.data.meshes.new(name="TriangleStripSet")
importMesh_ReadVertices(bpymesh, geom, ancestry)
counts = geom.getFieldAsArray('fanCount', 0, ancestry)
- bpymesh.tessfaces.add(sum([n - 2 for n in counts]))
+ num_polys = sum([n - 2 for n in counts])
+ bpymesh.loops.add(num_polys * 3)
+ bpymesh.polygons.add(num_polys)
+ bpymesh.polygons.foreach_set("loop_start", range(0, num_polys * 3, 3))
+ bpymesh.polygons.foreach_set("loop_total", (3,) * num_polys)
def triangles():
b = 0
@@ -1860,11 +1875,11 @@ def importMesh_TriangleFanSet(geom, ancestry, bpyima):
yield b + j + cw
yield b + j + 1 - cw
b += counts[i]
- bpymesh.tessfaces.foreach_set("vertices", [x for x in triangles()])
- return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry, bpyima)
+ bpymesh.polygons.foreach_set("vertices", [x for x in triangles()])
+ return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry)
-def importMesh_IndexedFaceSet(geom, ancestry, bpyima):
+def importMesh_IndexedFaceSet(geom, ancestry):
# Saw the following structure in X3Ds: the first mesh has a huge set
# of vertices and a reasonably sized index. The rest of the meshes
# reference the Coordinate node from the first one, and have their
@@ -1953,91 +1968,95 @@ def importMesh_IndexedFaceSet(geom, ancestry, bpyima):
normal_index = geom.getFieldAsArray('normalIndex', 0, ancestry)
if per_vertex:
co = [co for f in processPerVertexIndex(normal_index)
- for v in f for co in vectors[v]]
+ for v in f
+ for co in vectors[v]]
bpymesh.vertices.foreach_set("normal", co)
else:
- co = [co for (i, f) in enumerate(faces) for j in f
- for co in vectors[normal_index[i] if normal_index else i]]
+ co = [co for (i, f) in enumerate(faces)
+ for j in f
+ for co in vectors[normal_index[i] if normal_index else i]]
bpymesh.polygons.foreach_set("normal", co)
# Apply vertex/face colors
colors = geom.getChildBySpec(['ColorRGBA', 'Color'])
if colors:
if colors.getSpec() == 'ColorRGBA':
- # Array of arrays; no need to flatten
- rgb = [c[:3] for c
- in colors.getFieldAsArray('color', 4, ancestry)]
+ rgb = colors.getFieldAsArray('color', 4, ancestry)
else:
- rgb = colors.getFieldAsArray('color', 3, ancestry)
+ # Array of arrays; no need to flatten
+ rgb = [c + [1.0] for c in colors.getFieldAsArray('color', 3, ancestry)]
- color_per_vertex = geom.getFieldAsBool('colorPerVertex',
- True, ancestry)
+ color_per_vertex = geom.getFieldAsBool('colorPerVertex', True, ancestry)
color_index = geom.getFieldAsArray('colorIndex', 0, ancestry)
d = bpymesh.vertex_colors.new().data
if color_per_vertex:
cco = [cco for f in processPerVertexIndex(color_index)
- for v in f for cco in rgb[v]]
+ for v in f
+ for cco in rgb[v]]
elif color_index: # Color per face with index
- cco = [cco for (i, f) in enumerate(faces) for j in f
- for cco in rgb[color_index[i]]]
+ cco = [cco for (i, f) in enumerate(faces)
+ for j in f
+ for cco in rgb[color_index[i]]]
else: # Color per face without index
- cco = [cco for (i, f) in enumerate(faces) for j in f
- for cco in rgb[i]]
+ cco = [cco for (i, f) in enumerate(faces)
+ for j in f
+ for cco in rgb[i]]
d.foreach_set('color', cco)
- # Texture
- if bpyima:
- tex_coord = geom.getChildBySpec('TextureCoordinate')
- if tex_coord:
- tex_coord_points = tex_coord.getFieldAsArray('point', 2, ancestry)
- tex_index = geom.getFieldAsArray('texCoordIndex', 0, ancestry)
- tex_index = processPerVertexIndex(tex_index)
- loops = [co for f in tex_index
- for v in f for co in tex_coord_points[v]]
- else:
- x_min = x_max = y_min = y_max = z_min = z_max = None
- for f in faces:
- # Unused vertices don't participate in size; X3DOM does so
- for v in f:
- (x, y, z) = points[v]
- if x_min is None or x < x_min:
- x_min = x
- if x_max is None or x > x_max:
- x_max = x
- if y_min is None or y < y_min:
- y_min = y
- if y_max is None or y > y_max:
- y_max = y
- if z_min is None or z < z_min:
- z_min = z
- if z_max is None or z > z_max:
- z_max = z
-
- mins = (x_min, y_min, z_min)
- deltas = (x_max - x_min, y_max - y_min, z_max - z_min)
- axes = [0, 1, 2]
- axes.sort(key=lambda a: (-deltas[a], a))
- # Tuple comparison breaks ties
- (s_axis, t_axis) = axes[0:2]
- s_min = mins[s_axis]
- ds = deltas[s_axis]
- t_min = mins[t_axis]
- dt = deltas[t_axis]
-
- def generatePointCoords(pt):
- return (pt[s_axis] - s_min) / ds, (pt[t_axis] - t_min) / dt
- loops = [co for f in faces for v in f
- for co in generatePointCoords(points[v])]
-
- importMesh_ApplyTextureToLoops(bpymesh, bpyima, loops)
+ # Texture coordinates (UVs)
+ tex_coord = geom.getChildBySpec('TextureCoordinate')
+ if tex_coord:
+ tex_coord_points = tex_coord.getFieldAsArray('point', 2, ancestry)
+ tex_index = geom.getFieldAsArray('texCoordIndex', 0, ancestry)
+ tex_index = processPerVertexIndex(tex_index)
+ loops = [co for f in tex_index
+ for v in f
+ for co in tex_coord_points[v]]
+ else:
+ x_min = x_max = y_min = y_max = z_min = z_max = None
+ for f in faces:
+ # Unused vertices don't participate in size; X3DOM does so
+ for v in f:
+ (x, y, z) = points[v]
+ if x_min is None or x < x_min:
+ x_min = x
+ if x_max is None or x > x_max:
+ x_max = x
+ if y_min is None or y < y_min:
+ y_min = y
+ if y_max is None or y > y_max:
+ y_max = y
+ if z_min is None or z < z_min:
+ z_min = z
+ if z_max is None or z > z_max:
+ z_max = z
+
+ mins = (x_min, y_min, z_min)
+ deltas = (x_max - x_min, y_max - y_min, z_max - z_min)
+ axes = [0, 1, 2]
+ axes.sort(key=lambda a: (-deltas[a], a))
+ # Tuple comparison breaks ties
+ (s_axis, t_axis) = axes[0:2]
+ s_min = mins[s_axis]
+ ds = deltas[s_axis]
+ t_min = mins[t_axis]
+ dt = deltas[t_axis]
+
+ def generatePointCoords(pt):
+ return (pt[s_axis] - s_min) / ds, (pt[t_axis] - t_min) / dt
+ loops = [co for f in faces
+ for v in f
+ for co in generatePointCoords(points[v])]
+
+ importMesh_ApplyTextureToLoops(bpymesh, loops)
bpymesh.validate()
bpymesh.update()
return bpymesh
-def importMesh_ElevationGrid(geom, ancestry, bpyima):
+def importMesh_ElevationGrid(geom, ancestry):
height = geom.getFieldAsArray('height', 0, ancestry)
x_dim = geom.getFieldAsInt('xDimension', 0, ancestry)
x_spacing = geom.getFieldAsFloat('xSpacing', 1, ancestry)
@@ -2052,17 +2071,22 @@ def importMesh_ElevationGrid(geom, ancestry, bpyima):
for w in (x * x_spacing, height[x_dim * z + x], z * z_spacing)]
bpymesh.vertices.foreach_set("co", co)
- bpymesh.tessfaces.add((x_dim - 1) * (z_dim - 1))
+ num_polys = (x_dim - 1) * (z_dim - 1)
+ bpymesh.loops.add(num_polys * 4)
+ bpymesh.polygons.add(num_polys)
+ bpymesh.polygons.foreach_set("loop_start", range(0, num_polys * 4, 4))
+ bpymesh.polygons.foreach_set("loop_total", (4,) * num_polys)
# If the ccw is off, we flip the 2nd and the 4th vertices of each face.
- # For quad tessfaces, it's important that the final vertex index is not 0
- # (Blender treats it as a triangle then).
- # So simply reversing the face is not an option.
+ # For quad tessfaces, it was important that the final vertex index was not 0
+ # (Blender treated it as a triangle then).
+ # So simply reversing the face was not an option.
+ # With bmesh polygons, this has no importance anymore, but keep existing code for now.
verts = [i for x in range(x_dim - 1) for z in range(z_dim - 1)
for i in (z * x_dim + x,
z * x_dim + x + 1 if ccw else (z + 1) * x_dim + x,
(z + 1) * x_dim + x + 1,
(z + 1) * x_dim + x if ccw else z * x_dim + x + 1)]
- bpymesh.tessfaces.foreach_set("vertices_raw", verts)
+ bpymesh.polygons.foreach_set("vertices", verts)
importMesh_ApplyNormals(bpymesh, geom, ancestry)
# ApplyColors won't work here; faces are quads, and also per-face
@@ -2076,60 +2100,49 @@ def importMesh_ElevationGrid(geom, ancestry, bpyima):
else:
rgb = colors.getFieldAsArray('color', 3, ancestry)
- tc = bpymesh.tessface_vertex_colors.new()
- tcd = tc.data
+ tc = bpymesh.vertex_colors.new().data
if geom.getFieldAsBool('colorPerVertex', True, ancestry):
# Per-vertex coloring
# Note the 2/4 flip here
- tcd.foreach_set("color1", [c for x in range(x_dim - 1)
- for z in range(z_dim - 1)
- for c in rgb[z * x_dim + x]])
- tcd.foreach_set("color2" if ccw else "color4",
- [c for x in range(x_dim - 1)
- for z in range(z_dim - 1)
- for c in rgb[z * x_dim + x + 1]])
- tcd.foreach_set("color3", [c for x in range(x_dim - 1)
- for z in range(z_dim - 1)
- for c in rgb[(z + 1) * x_dim + x + 1]])
- tcd.foreach_set("color4" if ccw else "color2",
- [c for x in range(x_dim - 1)
- for z in range(z_dim - 1)
- for c in rgb[(z + 1) * x_dim + x]])
+ tc.foreach_set("color",
+ [c for x in range(x_dim - 1)
+ for z in range(z_dim - 1)
+ for rgb_idx in (z * x_dim + x,
+ z * x_dim + x + 1 if ccw else (z + 1) * x_dim + x,
+ (z + 1) * x_dim + x + 1,
+ (z + 1) * x_dim + x if ccw else z * x_dim + x + 1)
+ for c in rgb[rgb_idx]])
else: # Coloring per face
- colors = [c for x in range(x_dim - 1)
- for z in range(z_dim - 1) for c in rgb[z * (x_dim - 1) + x]]
- tcd.foreach_set("color1", colors)
- tcd.foreach_set("color2", colors)
- tcd.foreach_set("color3", colors)
- tcd.foreach_set("color4", colors)
+ tc.foreach_set("color",
+ [c for x in range(x_dim - 1)
+ for z in range(z_dim - 1)
+ for rgb_idx in (z * (x_dim - 1) + x,) * 4
+ for c in rgb[rgb_idx]])
# Textures also need special treatment; it's all quads,
# and there's a builtin algorithm for coordinate generation
- if bpyima:
- tex_coord = geom.getChildBySpec('TextureCoordinate')
- if tex_coord:
- coord_points = tex_coord.getFieldAsArray('point', 2, ancestry)
- else:
- coord_points = [(i / (x_dim - 1), j / (z_dim - 1))
- for i in range(x_dim)
- for j in range(z_dim)]
-
- d = bpymesh.tessface_uv_textures.new().data
- for face in d: # No foreach_set for nonscalars
- face.image = bpyima
- # Rather than repeat the face/vertex algorithm from above, we read
- # the vertex index back from tessfaces. Might be suboptimal.
- uv = [i for face in bpymesh.tessfaces
- for vno in range(4)
- for i in coord_points[face.vertices[vno]]]
- d.foreach_set('uv_raw', uv)
+ tex_coord = geom.getChildBySpec('TextureCoordinate')
+ if tex_coord:
+ uvs = tex_coord.getFieldAsArray('point', 2, ancestry)
+ else:
+ uvs = [(i / (x_dim - 1), j / (z_dim - 1))
+ for i in range(x_dim)
+ for j in range(z_dim)]
+
+ d = bpymesh.uv_layers.new().data
+ # Rather than repeat the face/vertex algorithm from above, we read
+ # the vertex index back from polygon. Might be suboptimal.
+ uvs = [i for poly in bpymesh.polygons
+ for vidx in poly.vertices
+ for i in uvs[vidx]]
+ d.foreach_set('uv', uv)
bpymesh.validate()
bpymesh.update()
return bpymesh
-def importMesh_Extrusion(geom, ancestry, bpyima):
+def importMesh_Extrusion(geom, ancestry):
# Interestingly, the spec doesn't allow for vertex/face colors in this
# element, nor for normals.
# Since coloring and normals are not supported here, and also large
@@ -2230,15 +2243,15 @@ def importMesh_Extrusion(geom, ancestry, bpyima):
if orient:
mrot = orient[i] if len(orient) > 1 else orient[0]
if mrot:
- m *= mrot # Not sure about this. Counterexample???
+ m @= mrot # Not sure about this. Counterexample???
if scale:
mscale = scale[i] if len(scale) > 1 else scale[0]
if mscale:
- m *= mscale
+ m @= mscale
# First the cross-section 2-vector is scaled,
# then applied to the xz plane unit vectors
for cpt in cross:
- verts.append((spt + m * cpt).to_tuple())
+ verts.append((spt + m @ cpt).to_tuple())
# Could've done this with a single 4x4 matrix... Oh well
# The method from_pydata() treats correctly quads with final vertex
@@ -2275,60 +2288,58 @@ def importMesh_Extrusion(geom, ancestry, bpyima):
bpymesh = bpy.data.meshes.new(name="Extrusion")
bpymesh.from_pydata(verts, [], faces)
- # Polygons and loops here, not tessfaces. The way we deal with
- # textures in triangular meshes doesn't apply.
- if bpyima:
- # The structure of the loop array goes: cap, side, cap
- if begin_cap or end_cap: # Need dimensions
- x_min = x_max = z_min = z_max = None
- for c in cross:
- (x, z) = (c.x, c.z)
- if x_min is None or x < x_min:
- x_min = x
- if x_max is None or x > x_max:
- x_max = x
- if z_min is None or z < z_min:
- z_min = z
- if z_max is None or z > z_max:
- z_max = z
- dx = x_max - x_min
- dz = z_max - z_min
- cap_scale = dz if dz > dx else dx
-
- # Takes an index in the cross array, returns scaled
- # texture coords for cap texturing purposes
- def scaledLoopVertex(i):
- c = cross[i]
- return (c.x - x_min) / cap_scale, (c.z - z_min) / cap_scale
-
- # X3DOM uses raw cap shape, not a scaled one. So we will, too.
-
- loops = []
- mloops = bpymesh.loops
- if begin_cap: # vertex indices match the indices in cross
- # Rely on the loops in the mesh; don't repeat the face
- # generation logic here
- loops += [co for i in range(nc)
- for co in scaledLoopVertex(mloops[i].vertex_index)]
-
- # Sides
- # Same order of vertices as in face generation
- # We don't rely on the loops in the mesh; instead,
- # we repeat the face generation logic.
- loops += [co for s in range(nsf)
- for c in range(ncf)
- for v in flip(((c / ncf, s / nsf),
- ((c + 1) / ncf, s / nsf),
- ((c + 1) / ncf, (s + 1) / nsf),
- (c / ncf, (s + 1) / nsf)), ccw) for co in v]
-
- if end_cap:
- # Base loop index for end cap
- lb = ncf * nsf * 4 + (nc if begin_cap else 0)
- # Rely on the loops here too.
- loops += [co for i in range(nc) for co
- in scaledLoopVertex(mloops[lb + i].vertex_index % nc)]
- importMesh_ApplyTextureToLoops(bpymesh, bpyima, loops)
+ # The way we deal with textures in triangular meshes doesn't apply.
+ # The structure of the loop array goes: cap, side, cap
+ if begin_cap or end_cap: # Need dimensions
+ x_min = x_max = z_min = z_max = None
+ for c in cross:
+ (x, z) = (c.x, c.z)
+ if x_min is None or x < x_min:
+ x_min = x
+ if x_max is None or x > x_max:
+ x_max = x
+ if z_min is None or z < z_min:
+ z_min = z
+ if z_max is None or z > z_max:
+ z_max = z
+ dx = x_max - x_min
+ dz = z_max - z_min
+ cap_scale = dz if dz > dx else dx
+
+ # Takes an index in the cross array, returns scaled
+ # texture coords for cap texturing purposes
+ def scaledLoopVertex(i):
+ c = cross[i]
+ return (c.x - x_min) / cap_scale, (c.z - z_min) / cap_scale
+
+ # X3DOM uses raw cap shape, not a scaled one. So we will, too.
+
+ loops = []
+ mloops = bpymesh.loops
+ if begin_cap: # vertex indices match the indices in cross
+ # Rely on the loops in the mesh; don't repeat the face
+ # generation logic here
+ loops += [co for i in range(nc)
+ for co in scaledLoopVertex(mloops[i].vertex_index)]
+
+ # Sides
+ # Same order of vertices as in face generation
+ # We don't rely on the loops in the mesh; instead,
+ # we repeat the face generation logic.
+ loops += [co for s in range(nsf)
+ for c in range(ncf)
+ for v in flip(((c / ncf, s / nsf),
+ ((c + 1) / ncf, s / nsf),
+ ((c + 1) / ncf, (s + 1) / nsf),
+ (c / ncf, (s + 1) / nsf)), ccw) for co in v]
+
+ if end_cap:
+ # Base loop index for end cap
+ lb = ncf * nsf * 4 + (nc if begin_cap else 0)
+ # Rely on the loops here too.
+ loops += [co for i in range(nc) for co
+ in scaledLoopVertex(mloops[lb + i].vertex_index % nc)]
+ importMesh_ApplyTextureToLoops(bpymesh, loops)
bpymesh.validate(True)
bpymesh.update()
@@ -2339,7 +2350,7 @@ def importMesh_Extrusion(geom, ancestry, bpyima):
# Line and point sets
-def importMesh_LineSet(geom, ancestry, bpyima):
+def importMesh_LineSet(geom, ancestry):
# TODO: line display properties are ignored
# Per-vertex color is ignored
coord = geom.getChildBySpec('Coordinate')
@@ -2438,7 +2449,7 @@ def importMesh_PointSet(geom, ancestry, _):
GLOBALS['CIRCLE_DETAIL'] = 12
-def importMesh_Sphere(geom, ancestry, bpyima):
+def importMesh_Sphere(geom, ancestry):
# solid is ignored.
# Extra field 'subdivision="n m"' attribute, specifying how many
# rings and segments to use (X3DOM).
@@ -2467,7 +2478,7 @@ def importMesh_Sphere(geom, ancestry, bpyima):
-cos(lou * seg) * sin(lau * ring))]
bpymesh.vertices.foreach_set('co', co)
- tf = bpymesh.tessfaces
+ tf = bpymesh.polygons
tf.add(ns * nr)
vb = 2 + (nr - 2) * ns # First vertex index for the bottom cap
fb = (nr - 1) * ns # First face index for the bottom cap
@@ -2476,10 +2487,7 @@ def importMesh_Sphere(geom, ancestry, bpyima):
# face creation. Can't easily do foreach_set, 'cause caps are triangles and
# sides are quads.
- if bpyima:
- tex = bpymesh.tessface_uv_textures.new().data
- for face in tex: # No foreach_set for nonscalars
- face.image = bpyima
+ tex = bpymesh.uv_layers.new().data
# Faces go in order: top cap, sides, bottom cap.
# Sides go by ring then by segment.
@@ -2491,13 +2499,16 @@ def importMesh_Sphere(geom, ancestry, bpyima):
for seg in range(ns):
tf[seg].vertices = (0, seg + 2, (seg + 1) % ns + 2)
tf[fb + seg].vertices = (1, vb + (seg + 1) % ns, vb + seg)
- if bpyima:
- tex[seg].uv = (((seg + 0.5) / ns, 1),
- (seg / ns, 1 - 1 / nr),
- ((seg + 1) / ns, 1 - 1 / nr))
- tex[fb + seg].uv = (((seg + 0.5) / ns, 0),
- ((seg + 1) / ns, 1 / nr),
- (seg / ns, 1 / nr))
+ for lidx, uv in zip(tf[seg].loops,
+ (((seg + 0.5) / ns, 1),
+ (seg / ns, 1 - 1 / nr),
+ ((seg + 1) / ns, 1 - 1 / nr))):
+ tex[lidx].uv = uv
+ for lidx, uv in zip(tf[fb + seg].loops,
+ (((seg + 0.5) / ns, 0),
+ ((seg + 1) / ns, 1 / nr),
+ (seg / ns, 1 / nr))):
+ tex[lidx].uv = uv
# Sides
# Side face vertices go in order: down right up left
@@ -2511,18 +2522,19 @@ def importMesh_Sphere(geom, ancestry, bpyima):
for seg in range(ns):
nseg = (seg + 1) % ns
tf[rfb + seg].vertices_raw = (tvb + seg, bvb + seg, bvb + nseg, tvb + nseg)
- if bpyima:
- tex[rfb + seg].uv_raw = (seg / ns, 1 - (ring + 1) / nr,
- seg / ns, 1 - (ring + 2) / nr,
- (seg + 1) / ns, 1 - (ring + 2) / nr,
- (seg + 1) / ns, 1 - (ring + 1) / nr)
+ for lidx, uv in zip(tf[rfb + seg].loops,
+ ((seg / ns, 1 - (ring + 1) / nr),
+ (seg / ns, 1 - (ring + 2) / nr),
+ ((seg + 1) / ns, 1 - (ring + 2) / nr),
+ ((seg + 1) / ns, 1 - (ring + 1) / nr))):
+ tex[lidx].uv = uv
bpymesh.validate(False)
bpymesh.update()
return bpymesh
-def importMesh_Cylinder(geom, ancestry, bpyima):
+def importMesh_Cylinder(geom, ancestry):
# solid is ignored
# no ccw in this element
# Extra parameter subdivision="n" - how many faces to use
@@ -2560,29 +2572,27 @@ def importMesh_Cylinder(geom, ancestry, bpyima):
bpymesh.validate(False)
- # Polygons here, not tessfaces
# The structure of the loop array goes: cap, side, cap.
- if bpyima:
- loops = []
- if side:
- loops += [co for i in range(n)
- for co in ((i + 1) / n, 0, (i + 1) / n, 1, i / n, 1, i / n, 0)]
+ loops = []
+ if side:
+ loops += [co for i in range(n)
+ for co in ((i + 1) / n, 0, (i + 1) / n, 1, i / n, 1, i / n, 0)]
- if top:
- loops += [0.5 + co / 2 for i in range(n)
- for co in (-sin(angle * i), cos(angle * i))]
+ if top:
+ loops += [0.5 + co / 2 for i in range(n)
+ for co in (-sin(angle * i), cos(angle * i))]
- if bottom:
- loops += [0.5 - co / 2 for i in range(n - 1, -1, -1)
- for co in (sin(angle * i), cos(angle * i))]
+ 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)
+ importMesh_ApplyTextureToLoops(bpymesh, loops)
bpymesh.update()
return bpymesh
-def importMesh_Cone(geom, ancestry, bpyima):
+def importMesh_Cone(geom, ancestry):
# Solid ignored
# Extra parameter subdivision="n" - how many faces to use
n = geom.getFieldAsInt('subdivision', GLOBALS['CIRCLE_DETAIL'], ancestry)
@@ -2610,21 +2620,20 @@ def importMesh_Cone(geom, ancestry, bpyima):
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)
+ 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, loops)
bpymesh.update()
return bpymesh
-def importMesh_Box(geom, ancestry, bpyima):
+def importMesh_Box(geom, ancestry):
# Solid is ignored
# No ccw in this element
(dx, dy, dz) = geom.getFieldAsFloatTuple('size', (2.0, 2.0, 2.0), ancestry)
@@ -2641,8 +2650,11 @@ def importMesh_Box(geom, ancestry, bpyima):
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', (
+ bpymesh.loops.add(6 * 4)
+ bpymesh.polygons.add(6)
+ bpymesh.polygons.foreach_set('loop_start', range(0, 6 * 4, 4))
+ bpymesh.polygons.foreach_set('loop_total', (4,) * 6)
+ bpymesh.polygons.foreach_set('vertices', (
0, 1, 2, 3, # +y
4, 0, 3, 7, # +x
7, 3, 2, 6, # -z
@@ -2651,17 +2663,14 @@ def importMesh_Box(geom, ancestry, bpyima):
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))
+ d = bpymesh.uv_layers.new().data
+ d.foreach_set('uv', (
+ 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))
bpymesh.update()
return bpymesh
@@ -2676,6 +2685,7 @@ def appearance_CreateMaterial(vrmlname, mat, ancestry, is_vcol):
# 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)
+ return # XXX For now...
bpymat.ambient = mat.getFieldAsFloat('ambientIntensity', 0.2, ancestry)
diff_color = mat.getFieldAsFloatTuple('diffuseColor',
[0.8, 0.8, 0.8],
@@ -2707,6 +2717,7 @@ def appearance_CreateDefaultMaterial():
# (but possibly with a texture).
bpymat = bpy.data.materials.new("Material")
+ return # XXX For now...
bpymat.ambient = 0.2
bpymat.diffuse_color = [0.8, 0.8, 0.8]
bpymat.mirror_color = (0, 0, 0)
@@ -2809,7 +2820,7 @@ def appearance_LoadTexture(tex_node, ancestry, node):
def appearance_ExpandCachedMaterial(bpymat):
- if bpymat.texture_slots[0] is not None:
+ if 0 and bpymat.texture_slots[0] is not None:
bpyima = bpymat.texture_slots[0].texture.image
tex_has_alpha = bpyima.use_alpha
return (bpymat, bpyima, tex_has_alpha)
@@ -2846,10 +2857,10 @@ def appearance_Create(vrmlname, material, tex_node, ancestry, node, is_vcol):
if tex_node: # Texture caching inside there
bpyima = appearance_LoadTexture(tex_node, ancestry, node)
- if is_vcol:
+ if 0 & is_vcol:
bpymat.use_vertex_color_paint = True
- if bpyima:
+ if 0 and bpyima:
tex_has_alpha = bpyima.use_alpha
texture = bpy.data.textures.new(bpyima.name, 'IMAGE')
@@ -3003,22 +3014,19 @@ def importShape_ProcessObject(
if bpymat:
bpydata.materials.append(bpymat)
- if bpydata.tessface_uv_textures:
- if has_alpha: # set the faces alpha flag?
- # transp = Mesh.FaceTranspModes.ALPHA
- for f in bpydata.tessface_uv_textures.active.data:
- f.blend_type = 'ALPHA'
+ if bpydata.uv_layers:
+ if has_alpha and bpymat: # set the faces alpha flag?
+ bpymat.blend_method = 'BLEND'
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]
+ for l in bpydata.uv_layers.active.data:
+ luv = l.uv
+ uv_copy.x = luv[0]
+ uv_copy.y = luv[1]
+ l.uv[:] = (uv_copy @ texmtx)[0:2]
- fuv[i] = (uv_copy * texmtx)[0:2]
# Done transforming the texture
# TODO: check if per-polygon textures are supported here.
elif type(bpydata) == bpy.types.TextCurve:
@@ -3031,13 +3039,14 @@ def importShape_ProcessObject(
# bpymesh.transform(getFinalMatrix(node))
bpyob = node.blendObject = bpy.data.objects.new(vrmlname, bpydata)
bpyob.matrix_world = getFinalMatrix(node, None, ancestry, global_matrix)
- bpycollection.objects.link(bpyob).select_set(True)
+ bpycollection.objects.link(bpyob)
+ bpyob.select_set(True)
if DEBUG:
bpyob["source_line_no"] = geom.lineno
-def importText(geom, ancestry, bpyima):
+def importText(geom, ancestry):
fmt = geom.getChildBySpec('FontStyle')
size = fmt.getFieldAsFloat("size", 1, ancestry) if fmt else 1.
body = geom.getFieldAsString("string", None, ancestry)
@@ -3085,7 +3094,8 @@ def importShape(bpycollection, node, ancestry, global_matrix):
bpyob = node.blendData = node.blendObject = bpyob.copy()
# Could transform data, but better the object so we can instance the data
bpyob.matrix_world = getFinalMatrix(node, None, ancestry, global_matrix)
- bpycollection.objects.link(bpyob).select_set(True)
+ bpycollection.objects.link(bpyob)
+ bpyob.select_set(True)
return
vrmlname = node.getDefName()
@@ -3122,7 +3132,7 @@ def importShape(bpycollection, node, ancestry, global_matrix):
# geometries are easier to flip than others
geom_fn = geometry_importers.get(geom_spec)
if geom_fn is not None:
- bpydata = geom_fn(geom, ancestry, bpyima)
+ bpydata = geom_fn(geom, ancestry)
# There are no geometry importers that can legally return
# no object. It's either a bpy object, or an exception
@@ -3216,7 +3226,7 @@ def importLamp_SpotLight(node, ancestry):
# Convert
# lamps have their direction as -z, y==up
- mtx = Matrix.Translation(location) * Vector(direction).to_track_quat('-Z', 'Y').to_matrix().to_4x4()
+ mtx = Matrix.Translation(location) @ Vector(direction).to_track_quat('-Z', 'Y').to_matrix().to_4x4()
return bpylamp, mtx
@@ -3233,7 +3243,8 @@ def importLamp(bpycollection, node, spec, ancestry, global_matrix):
raise ValueError
bpyob = node.blendData = node.blendObject = bpy.data.objects.new(bpylamp.name, bpylamp)
- bpycollection.objects.link(bpyob).select_set(True)
+ bpycollection.objects.link(bpyob)
+ bpyob.select_set(True)
bpyob.matrix_world = getFinalMatrix(node, mtx, ancestry, global_matrix)
@@ -3256,10 +3267,11 @@ def importViewpoint(bpycollection, node, ancestry, global_matrix):
bpycam.angle = fieldOfView
- mtx = Matrix.Translation(Vector(position)) * translateRotation(orientation)
+ mtx = Matrix.Translation(Vector(position)) @ translateRotation(orientation)
bpyob = node.blendData = node.blendObject = bpy.data.objects.new(name, bpycam)
- bpycollection.objects.link(bpyob).select_set(True)
+ bpycollection.objects.link(bpyob)
+ bpyob.select_set(True)
bpyob.matrix_world = getFinalMatrix(node, mtx, ancestry, global_matrix)
@@ -3269,7 +3281,8 @@ def importTransform(bpycollection, node, ancestry, global_matrix):
name = 'Transform'
bpyob = node.blendData = node.blendObject = bpy.data.objects.new(name, None)
- bpycollection.objects.link(bpyob).select_set(True)
+ bpycollection.objects.link(bpyob)
+ bpyob.select_set(True)
bpyob.matrix_world = getFinalMatrix(node, None, ancestry, global_matrix)
@@ -3533,7 +3546,8 @@ def load_web3d(
node = defDict[key]
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)
- bpycollection.objects.link(node.blendObject).select_set(True)
+ bpycollection.objects.link(node.blendObject)
+ bpyob.select_set(True)
if node.blendData.animation_data is None:
node.blendData.animation_data_create()