gltf exporter: new feature: export 'Loose Points' and 'Loose Edges'
This commit is contained in:
parent
37af7e130b
commit
8d24537a6e
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2018-2019 The glTF-Blender-IO authors.
|
||||
# Copyright 2018-2021 The glTF-Blender-IO authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -15,7 +15,7 @@
|
|||
bl_info = {
|
||||
'name': 'glTF 2.0 format',
|
||||
'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
|
||||
"version": (1, 6, 4),
|
||||
"version": (1, 6, 5),
|
||||
'blender': (2, 91, 0),
|
||||
'location': 'File > Import-Export',
|
||||
'description': 'Import-Export as glTF 2.0',
|
||||
|
@ -263,6 +263,22 @@ class ExportGLTF2_Base:
|
|||
default=True
|
||||
)
|
||||
|
||||
use_mesh_edges: BoolProperty(
|
||||
name='Loose Edges',
|
||||
description=(
|
||||
'Export loose edges as lines, using the material from the first material slot'
|
||||
),
|
||||
default=False,
|
||||
)
|
||||
|
||||
use_mesh_vertices: BoolProperty(
|
||||
name='Loose Points',
|
||||
description=(
|
||||
'Export loose points as glTF points, using the material from the first material slot'
|
||||
),
|
||||
default=False,
|
||||
)
|
||||
|
||||
export_cameras: BoolProperty(
|
||||
name='Cameras',
|
||||
description='Export cameras',
|
||||
|
@ -444,10 +460,18 @@ class ExportGLTF2_Base:
|
|||
return ExportHelper.invoke(self, context, event)
|
||||
|
||||
def save_settings(self, context):
|
||||
# find all export_ props
|
||||
# find all props to save
|
||||
exceptional = [
|
||||
# options that don't start with 'export_'
|
||||
'use_selection',
|
||||
'use_mesh_edges',
|
||||
'use_mesh_vertices',
|
||||
]
|
||||
all_props = self.properties
|
||||
export_props = {x: getattr(self, x) for x in dir(all_props)
|
||||
if (x.startswith("export_") or x == "use_selection") and all_props.get(x) is not None}
|
||||
export_props = {
|
||||
x: getattr(self, x) for x in dir(all_props)
|
||||
if (x.startswith("export_") or x in exceptional) and all_props.get(x) is not None
|
||||
}
|
||||
|
||||
context.scene[self.scene_key] = export_props
|
||||
|
||||
|
@ -479,6 +503,8 @@ class ExportGLTF2_Base:
|
|||
export_settings['gltf_texcoords'] = self.export_texcoords
|
||||
export_settings['gltf_normals'] = self.export_normals
|
||||
export_settings['gltf_tangents'] = self.export_tangents and self.export_normals
|
||||
export_settings['gltf_loose_edges'] = self.use_mesh_edges
|
||||
export_settings['gltf_loose_points'] = self.use_mesh_vertices
|
||||
|
||||
if self.is_draco_available:
|
||||
export_settings['gltf_draco_mesh_compression'] = self.export_draco_mesh_compression_enable
|
||||
|
@ -692,6 +718,11 @@ class GLTF_PT_export_geometry(bpy.types.Panel):
|
|||
col.active = operator.export_normals
|
||||
col.prop(operator, 'export_tangents')
|
||||
layout.prop(operator, 'export_colors')
|
||||
|
||||
col = layout.column()
|
||||
col.prop(operator, 'use_mesh_edges')
|
||||
col.prop(operator, 'use_mesh_vertices')
|
||||
|
||||
layout.prop(operator, 'export_materials')
|
||||
col = layout.column()
|
||||
col.active = operator.export_materials == "EXPORT"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2018-2019 The glTF-Blender-IO authors.
|
||||
# Copyright 2018-2021 The glTF-Blender-IO authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -283,6 +283,90 @@ def extract_primitives(glTF, blender_mesh, library, blender_object, blender_vert
|
|||
'material': material_idx,
|
||||
})
|
||||
|
||||
if export_settings['gltf_loose_edges']:
|
||||
# Find loose edges
|
||||
loose_edges = [e for e in blender_mesh.edges if e.is_loose]
|
||||
blender_idxs = [vi for e in loose_edges for vi in e.vertices]
|
||||
|
||||
if blender_idxs:
|
||||
# Export one glTF vert per unique Blender vert in a loose edge
|
||||
blender_idxs = np.array(blender_idxs, dtype=np.uint32)
|
||||
blender_idxs, indices = np.unique(blender_idxs, return_inverse=True)
|
||||
|
||||
attributes = {}
|
||||
|
||||
attributes['POSITION'] = locs[blender_idxs]
|
||||
|
||||
for morph_i, vs in enumerate(morph_locs):
|
||||
attributes['MORPH_POSITION_%d' % morph_i] = vs[blender_idxs]
|
||||
|
||||
if skin:
|
||||
joints = [[] for _ in range(num_joint_sets)]
|
||||
weights = [[] for _ in range(num_joint_sets)]
|
||||
|
||||
for vi in blender_idxs:
|
||||
bones = vert_bones[vi]
|
||||
for j in range(0, 4 * num_joint_sets):
|
||||
if j < len(bones):
|
||||
joint, weight = bones[j]
|
||||
else:
|
||||
joint, weight = 0, 0.0
|
||||
joints[j//4].append(joint)
|
||||
weights[j//4].append(weight)
|
||||
|
||||
for i, (js, ws) in enumerate(zip(joints, weights)):
|
||||
attributes['JOINTS_%d' % i] = js
|
||||
attributes['WEIGHTS_%d' % i] = ws
|
||||
|
||||
primitives.append({
|
||||
'attributes': attributes,
|
||||
'indices': indices,
|
||||
'mode': 1, # LINES
|
||||
'material': 0,
|
||||
})
|
||||
|
||||
if export_settings['gltf_loose_points']:
|
||||
# Find loose points
|
||||
verts_in_edge = set(vi for e in blender_mesh.edges for vi in e.vertices)
|
||||
blender_idxs = [
|
||||
vi for vi, _ in enumerate(blender_mesh.vertices)
|
||||
if vi not in verts_in_edge
|
||||
]
|
||||
|
||||
if blender_idxs:
|
||||
blender_idxs = np.array(blender_idxs, dtype=np.uint32)
|
||||
|
||||
attributes = {}
|
||||
|
||||
attributes['POSITION'] = locs[blender_idxs]
|
||||
|
||||
for morph_i, vs in enumerate(morph_locs):
|
||||
attributes['MORPH_POSITION_%d' % morph_i] = vs[blender_idxs]
|
||||
|
||||
if skin:
|
||||
joints = [[] for _ in range(num_joint_sets)]
|
||||
weights = [[] for _ in range(num_joint_sets)]
|
||||
|
||||
for vi in blender_idxs:
|
||||
bones = vert_bones[vi]
|
||||
for j in range(0, 4 * num_joint_sets):
|
||||
if j < len(bones):
|
||||
joint, weight = bones[j]
|
||||
else:
|
||||
joint, weight = 0, 0.0
|
||||
joints[j//4].append(joint)
|
||||
weights[j//4].append(weight)
|
||||
|
||||
for i, (js, ws) in enumerate(zip(joints, weights)):
|
||||
attributes['JOINTS_%d' % i] = js
|
||||
attributes['WEIGHTS_%d' % i] = ws
|
||||
|
||||
primitives.append({
|
||||
'attributes': attributes,
|
||||
'mode': 0, # POINTS
|
||||
'material': 0,
|
||||
})
|
||||
|
||||
print_console('INFO', 'Primitives created: %d' % len(primitives))
|
||||
|
||||
return primitives
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2018-2019 The glTF-Blender-IO authors.
|
||||
# Copyright 2018-2021 The glTF-Blender-IO authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -54,7 +54,7 @@ def gather_primitives(
|
|||
material_idx = internal_primitive['material']
|
||||
material = None
|
||||
|
||||
if export_settings['gltf_materials'] == "EXPORT":
|
||||
if export_settings['gltf_materials'] == "EXPORT" and material_idx is not None:
|
||||
blender_material = None
|
||||
if material_names:
|
||||
i = material_idx if material_idx < len(material_names) else -1
|
||||
|
@ -73,7 +73,7 @@ def gather_primitives(
|
|||
extras=None,
|
||||
indices=internal_primitive['indices'],
|
||||
material=material,
|
||||
mode=None,
|
||||
mode=internal_primitive['mode'],
|
||||
targets=internal_primitive['targets']
|
||||
)
|
||||
primitives.append(primitive)
|
||||
|
@ -101,7 +101,8 @@ def __gather_cache_primitives(
|
|||
primitive = {
|
||||
"attributes": __gather_attributes(internal_primitive, blender_mesh, modifiers, export_settings),
|
||||
"indices": __gather_indices(internal_primitive, blender_mesh, modifiers, export_settings),
|
||||
"material": internal_primitive['material'],
|
||||
"mode": internal_primitive.get('mode'),
|
||||
"material": internal_primitive.get('material'),
|
||||
"targets": __gather_targets(internal_primitive, blender_mesh, modifiers, export_settings)
|
||||
}
|
||||
primitives.append(primitive)
|
||||
|
@ -109,7 +110,9 @@ def __gather_cache_primitives(
|
|||
return primitives
|
||||
|
||||
def __gather_indices(blender_primitive, blender_mesh, modifiers, export_settings):
|
||||
indices = blender_primitive['indices']
|
||||
indices = blender_primitive.get('indices')
|
||||
if indices is None:
|
||||
return None
|
||||
|
||||
# NOTE: Values used by some graphics APIs as "primitive restart" values are disallowed.
|
||||
# Specifically, the values 65535 (in UINT16) and 4294967295 (in UINT32) cannot be used as indices.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2018-2019 The glTF-Blender-IO authors.
|
||||
# Copyright 2018-2021 The glTF-Blender-IO authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -85,6 +85,10 @@ def __encode_primitive(primitive, dll, export_settings):
|
|||
attributes = primitive.attributes
|
||||
indices = primitive.indices
|
||||
|
||||
# Only do TRIANGLES primitives
|
||||
if primitive.mode not in [None, 4]:
|
||||
return
|
||||
|
||||
if 'POSITION' not in attributes:
|
||||
print_console('WARNING', 'Draco encoder: Primitive without positions encountered. Skipping.')
|
||||
return
|
||||
|
|
Loading…
Reference in New Issue