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).
This commit is contained in:
parent
d17b937569
commit
e8da70ab73
Notes:
blender-bot
2023-02-14 19:13:15 +01:00
Referenced by issue #71232, X3D Import does not handle Materials Referenced by issue #66534, X3D export in 2.80 does not save texture
|
@ -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()
|
||||
|
|
|
@ -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]
|
||||
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 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)
|
||||
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))
|
||||
# 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]
|
||||
|
||||
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:
|
||||
# transform by mtex
|
||||
loc = mesh_material_mtex[material_index].offset[:2]
|
||||
rot = 0.0
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
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)
|
||||
|
||||
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
|
||||
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)
|
||||
# ~ 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.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,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue