This commit is contained in:
wTechArtist
2025-06-18 16:25:59 +08:00
parent 0dc115fd23
commit 1df29d4da7
+364 -129
View File
@@ -146,27 +146,28 @@ class GLBPointCloudProcessor:
original_count = len(point_cloud.vertices)
total_original_points += original_count
# 获取顶点和颜色
vertices = point_cloud.vertices.copy()
# 获取原始点云的所有属性和状态
original_vertices = point_cloud.vertices.copy()
colors = None
# 获取颜色信息
if hasattr(point_cloud.visual, 'vertex_colors') and point_cloud.visual.vertex_colors is not None:
colors = point_cloud.visual.vertex_colors.copy()
elif hasattr(point_cloud, 'colors') and point_cloud.colors is not None:
colors = point_cloud.colors.copy()
# 初始化掩码(所有点都保留)
keep_mask = np.ones(len(vertices), dtype=bool)
keep_mask = np.ones(len(original_vertices), dtype=bool)
# 删除暗色点(默认启用)
# 删除暗色点(仅基于颜色,不改变顶点坐标)
if colors is not None:
removed_count = self._remove_dark_points(vertices, colors, keep_mask, black_threshold, processing_log)
removed_count = self._remove_dark_points(original_vertices, colors, keep_mask, black_threshold, processing_log)
processing_log.append(f"删除黑色点: {removed_count} 个")
else:
processing_log.append("跳过黑色点过滤: 点云无颜色信息")
# 应用掩码
filtered_vertices = vertices[keep_mask]
# 应用掩码,保留原始的顶点坐标
filtered_vertices = original_vertices[keep_mask]
filtered_colors = colors[keep_mask] if colors is not None else None
remaining_count = len(filtered_vertices)
@@ -175,25 +176,53 @@ class GLBPointCloudProcessor:
processing_log.append(f"点云 {name}: 原始 {original_count} -> 剩余 {remaining_count} (删除 {removed_count})")
# 创建处理后的点云
# 创建处理后的点云,保留所有原始属性
if remaining_count > 0:
processed_pc = trimesh.PointCloud(vertices=filtered_vertices, colors=filtered_colors)
# 使用原始点云作为模板,只更新顶点和颜色
processed_pc = point_cloud.copy()
processed_pc.vertices = filtered_vertices
if filtered_colors is not None:
processed_pc.visual.vertex_colors = filtered_colors
processed_point_clouds.append((name, processed_pc))
processing_log.append(f"保留点云 {name} 的所有原始属性和状态")
else:
processing_log.append(f"警告: 点云 {name} 处理后没有剩余点")
# 创建新的场景
# 直接修改原始场景,保持所有几何信息不变
if processed_point_clouds:
new_scene = trimesh.Scene()
# 使用原始场景作为基础,直接替换点云数据
new_scene = scene
# 添加处理后的点云
for name, pc in processed_point_clouds:
new_scene.add_geometry(pc, node_name=name)
# 直接修改原始场景中的点云几何体,保持变换不变
for name, processed_pc in processed_point_clouds:
if isinstance(scene, trimesh.Scene):
# 获取原始几何体
if name in scene.geometry:
original_geometry = scene.geometry[name]
# 如果是点云,直接修改顶点和颜色
if isinstance(original_geometry, trimesh.PointCloud):
original_geometry.vertices = processed_pc.vertices
if hasattr(processed_pc.visual, 'vertex_colors') and processed_pc.visual.vertex_colors is not None:
original_geometry.visual.vertex_colors = processed_pc.visual.vertex_colors
processing_log.append(f"直接修改原始点云 {name},保持所有变换和属性不变")
else:
# 如果不是点云类型,替换整个几何体但保持变换
scene.delete_geometry(name)
scene.add_geometry(processed_pc, node_name=name)
processing_log.append(f"替换几何体 {name},尝试保持变换")
else:
# 新增几何体
scene.add_geometry(processed_pc, node_name=name)
processing_log.append(f"添加新点云 {name}")
else:
# 单个几何体的情况
new_scene = processed_pc
processing_log.append("单个几何体,直接使用处理后的点云")
# 添加其他几何体(如相机模型)
for name, geometry in other_geometries:
new_scene.add_geometry(geometry, node_name=name)
processing_log.append(f"保留几何体: {name}")
processing_log.append("直接修改原始场景,所有变换矩阵和几何属性完全保持不变")
# 生成输出路径
output_path = self._generate_output_path(output_filename)
@@ -208,9 +237,20 @@ class GLBPointCloudProcessor:
file_size = os.path.getsize(output_path)
processing_log.append(f"GLB文件保存成功,文件大小: {file_size} bytes")
# 验证输出文件的一致性
try:
# 加载输出文件进行验证
verification_scene = trimesh.load(output_path)
processing_log.append("文件验证: 输出文件可正常加载")
# 检查是否保留了场景结构
if isinstance(scene, trimesh.Scene) and isinstance(verification_scene, trimesh.Scene):
processing_log.append(f"场景结构验证: 原始 {len(scene.geometry)} 个对象 -> 输出 {len(verification_scene.geometry)} 个对象")
except Exception as e:
processing_log.append(f"文件验证警告: {str(e)}")
processing_log.append("GLB点云黑色点清理完成!")
processing_log.append("GLB点云黑色点清理完成! 已保留原始模型的大小、朝向和几何属性")
return (output_path,)
else:
error_msg = "GLB文件保存失败"
@@ -298,7 +338,7 @@ class GLBPointCloudProcessor:
class GLBPointCloudBounds:
"""GLB点云包围盒计算器 - 计算包围盒并生成带可视化的点云文件"""
"""GLB点云包围盒计算器 - 计算包围盒并生成带可视化的预览文件(原模型数据保持不变)"""
@classmethod
def INPUT_TYPES(cls):
@@ -306,7 +346,7 @@ class GLBPointCloudBounds:
"required": {
"glb_file_path": ("STRING", {
"default": "",
"tooltip": "GLB点云文件路径:输入需要计算包围盒的GLB格式点云文件。支持绝对路径或相对于ComfyUI output目录的相对路径"
"tooltip": "GLB点云文件路径:输入需要计算包围盒的GLB格式点云文件。支持绝对路径或相对于ComfyUI output目录的相对路径。注意:此节点在原模型基础上添加预览信息,原模型数据保持不变"
}),
},
"optional": {
@@ -350,7 +390,7 @@ class GLBPointCloudBounds:
"scale_json",
)
OUTPUT_TOOLTIPS = [
"输出GLB文件路径 - 包含原始点云+包围盒可视化+坐标轴的完整点云文件",
"带预览的GLB文件路径 - 包含原始点云+包围盒可视化+坐标轴的完整点云文件",
"纯净的scale数组JSON: {\"scale\": [长, 宽, 高]} - 仅包含scale信息,可直接用于3D引擎缩放",
]
OUTPUT_NODE = True
@@ -403,21 +443,27 @@ class GLBPointCloudBounds:
processing_log.append("正在加载GLB文件...")
scene = trimesh.load(input_path)
# 收集所有点云数据
# 收集所有点云数据,考虑变换矩阵
all_vertices = []
point_cloud_count = 0
if isinstance(scene, trimesh.Scene):
for name, geometry in scene.geometry.items():
if isinstance(geometry, trimesh.PointCloud):
all_vertices.append(geometry.vertices)
point_cloud_count += 1
processing_log.append(f"发现点云: {name}, 点数: {len(geometry.vertices)}")
elif hasattr(geometry, 'vertices') and geometry.vertices is not None:
# 处理可能被转换为Mesh的点云
all_vertices.append(geometry.vertices)
point_cloud_count += 1
processing_log.append(f"发现几何体(作为点云处理): {name}, 点数: {len(geometry.vertices)}")
for node_name in scene.graph.nodes:
if node_name in scene.geometry:
geometry = scene.geometry[node_name]
transform_matrix = scene.graph[node_name][0] # 获取变换矩阵
if hasattr(geometry, 'vertices') and geometry.vertices is not None:
# 应用变换矩阵获取真实世界坐标
if transform_matrix is not None and not np.allclose(transform_matrix, np.eye(4)):
world_vertices = trimesh.transformations.transform_points(geometry.vertices, transform_matrix)
processing_log.append(f"发现几何体: {node_name}, 点数: {len(geometry.vertices)}, 已应用变换矩阵")
else:
world_vertices = geometry.vertices.copy()
processing_log.append(f"发现几何体: {node_name}, 点数: {len(geometry.vertices)}, 无变换")
all_vertices.append(world_vertices)
point_cloud_count += 1
elif isinstance(scene, trimesh.PointCloud):
all_vertices.append(scene.vertices)
point_cloud_count = 1
@@ -436,10 +482,10 @@ class GLBPointCloudBounds:
processing_log.append(f"错误: {error_msg}")
return ("", "")
# 合并所有顶点
# 合并所有顶点(已经是世界坐标)
combined_vertices = np.vstack(all_vertices)
total_points = len(combined_vertices)
processing_log.append(f"合并了 {point_cloud_count} 个点云,总点数: {total_points}")
processing_log.append(f"合并了 {point_cloud_count} 个几何体,总点数: {total_points} (已应用变换矩阵)")
# 计算包围盒
processing_log.append(f"计算包围盒类型: {bounding_box_type}")
@@ -451,8 +497,6 @@ class GLBPointCloudBounds:
extents = max_point - min_point
center = (min_point + max_point) / 2
processing_log.append(f"AABB计算完成:")
processing_log.append(f" 最小点: [{min_point[0]:.6f}, {min_point[1]:.6f}, {min_point[2]:.6f}]")
processing_log.append(f" 最大点: [{max_point[0]:.6f}, {max_point[1]:.6f}, {max_point[2]:.6f}]")
@@ -465,15 +509,13 @@ class GLBPointCloudBounds:
try:
to_origin, obb_extents = trimesh.bounds.oriented_bounds(combined_vertices)
# 计算OBB的中心点和角点
# 计算OBB的中心点
obb_center = -to_origin[:3, 3] # 变换矩阵的平移部分的负值
center = obb_center # 设置center变量
extents = obb_extents
processing_log.append(f"OBB计算完成:")
processing_log.append(f" 中心点: [{obb_center[0]:.6f}, {obb_center[1]:.6f}, {obb_center[2]:.6f}]")
processing_log.append(f" 中心点: [{center[0]:.6f}, {center[1]:.6f}, {center[2]:.6f}]")
processing_log.append(f" 尺寸: [{extents[0]:.6f}, {extents[1]:.6f}, {extents[2]:.6f}]")
processing_log.append(f" 体积: {np.prod(extents):.6f}")
@@ -508,7 +550,7 @@ class GLBPointCloudBounds:
processing_log.append(f" 宽度(Y): {scale_array[1]:.6f} {units}")
processing_log.append(f" 高度(Z): {scale_array[2]:.6f} {units}")
# 生成带可视化的点云文件
# 生成带可视化的点云文件(原模型数据不变,仅添加预览)
output_glb_path = ""
try:
@@ -590,48 +632,65 @@ class GLBPointCloudBounds:
wireframe_density, enhance_visibility, output_filename, processing_log):
"""生成包含原始点云、包围盒线框和坐标轴的可视化点云文件"""
try:
# 重新加载原始GLB文件以保持颜色信息
# 直接使用已加载的原始场景数据,避免重新加载可能改变朝向
input_path = self._get_current_input_path()
original_scene = trimesh.load(input_path)
# 提取原始点云数据(保持颜色)
# 提取原始点云数据(完全保持原始状态)
all_vertices = []
all_colors = []
original_point_count = 0
# 使用之前已经加载的combined_vertices作为基础,重新从原始场景提取完整数据
original_scene = trimesh.load(input_path)
# 创建一个新的场景,完全保持原始场景的结构和变换
visualization_scene = trimesh.Scene()
# 保持原始场景的完整结构
if isinstance(original_scene, trimesh.Scene):
for name, geometry in original_scene.geometry.items():
if isinstance(geometry, trimesh.PointCloud):
all_vertices.append(geometry.vertices)
# 保持原始颜色
if hasattr(geometry.visual, 'vertex_colors') and geometry.visual.vertex_colors is not None:
colors = geometry.visual.vertex_colors.copy()
elif hasattr(geometry, 'colors') and geometry.colors is not None:
colors = geometry.colors.copy()
else:
# 如果没有颜色信息,使用白色
colors = np.tile([255, 255, 255, 255], (len(geometry.vertices), 1))
# 完全复制原始场景的所有几何体和变换
for node_name in original_scene.graph.nodes:
if node_name in original_scene.geometry:
geometry = original_scene.geometry[node_name]
transform_matrix = original_scene.graph[node_name][0] # 获取变换矩阵
# 确保颜色格式一致 (RGBA, 0-255)
colors = self._normalize_colors(colors)
all_colors.append(colors)
original_point_count += len(geometry.vertices)
processing_log.append(f"保留原始点云: {name}, {len(geometry.vertices):,} 个点,颜色已保持")
elif hasattr(geometry, 'vertices') and geometry.vertices is not None:
all_vertices.append(geometry.vertices)
# 处理可能被转换为Mesh的点云
if hasattr(geometry.visual, 'vertex_colors') and geometry.visual.vertex_colors is not None:
colors = geometry.visual.vertex_colors.copy()
else:
colors = np.tile([255, 255, 255, 255], (len(geometry.vertices), 1))
# 完全复制几何体,保持所有属性
copied_geometry = geometry.copy()
# 确保颜色格式一致 (RGBA, 0-255)
colors = self._normalize_colors(colors)
all_colors.append(colors)
original_point_count += len(geometry.vertices)
processing_log.append(f"保留原始几何体: {name}, {len(geometry.vertices):,} 个点,颜色已保持")
# 添加到新场景,保持原始的变换矩阵
visualization_scene.add_geometry(copied_geometry, node_name=node_name, transform=transform_matrix)
# 提取顶点用于统计(注意:这里用于显示统计,真实包围盒计算已在前面完成)
if hasattr(geometry, 'vertices') and geometry.vertices is not None:
# 这里不需要再次应用变换,因为包围盒计算已经在combined_vertices中处理过了
all_vertices.append(geometry.vertices)
# 保持原始颜色
if isinstance(geometry, trimesh.PointCloud):
if hasattr(geometry.visual, 'vertex_colors') and geometry.visual.vertex_colors is not None:
colors = geometry.visual.vertex_colors.copy()
elif hasattr(geometry, 'colors') and geometry.colors is not None:
colors = geometry.colors.copy()
else:
colors = np.tile([255, 255, 255, 255], (len(geometry.vertices), 1))
else:
if hasattr(geometry.visual, 'vertex_colors') and geometry.visual.vertex_colors is not None:
colors = geometry.visual.vertex_colors.copy()
else:
colors = np.tile([200, 200, 200, 255], (len(geometry.vertices), 1))
# 确保颜色格式一致 (RGBA, 0-255)
colors = self._normalize_colors(colors)
all_colors.append(colors)
original_point_count += len(geometry.vertices)
processing_log.append(f"完全保持原始几何体: {node_name}, 变换矩阵和所有属性已保留")
elif isinstance(original_scene, trimesh.PointCloud):
# 单个点云,直接复制
visualization_scene = original_scene.copy()
all_vertices.append(original_scene.vertices)
if hasattr(original_scene.visual, 'vertex_colors') and original_scene.visual.vertex_colors is not None:
colors = original_scene.visual.vertex_colors.copy()
elif hasattr(original_scene, 'colors') and original_scene.colors is not None:
@@ -639,63 +698,71 @@ class GLBPointCloudBounds:
else:
colors = np.tile([255, 255, 255, 255], (len(original_scene.vertices), 1))
# 确保颜色格式一致 (RGBA, 0-255)
colors = self._normalize_colors(colors)
all_colors.append(colors)
original_point_count = len(original_scene.vertices)
processing_log.append(f"保留原始点云: {original_point_count:,} 个点,颜色已保持")
elif hasattr(original_scene, 'vertices') and original_scene.vertices is not None:
all_vertices.append(original_scene.vertices)
if hasattr(original_scene.visual, 'vertex_colors') and original_scene.visual.vertex_colors is not None:
colors = original_scene.visual.vertex_colors.copy()
else:
colors = np.tile([255, 255, 255, 255], (len(original_scene.vertices), 1))
# 确保颜色格式一致 (RGBA, 0-255)
colors = self._normalize_colors(colors)
all_colors.append(colors)
original_point_count = len(original_scene.vertices)
processing_log.append(f"保留原始几何体: {original_point_count:,} 个点,颜色已保持")
processing_log.append(f"完全保持原始点云: {original_point_count:,} 个点")
processing_log.append(f"原始点云总计: {original_point_count:,} 个点,颜色信息完整保留")
else:
# 单个几何体,转换为场景保持结构
visualization_scene.add_geometry(original_scene.copy(), node_name="main_geometry")
if hasattr(original_scene, 'vertices') and original_scene.vertices is not None:
all_vertices.append(original_scene.vertices)
if hasattr(original_scene.visual, 'vertex_colors') and original_scene.visual.vertex_colors is not None:
colors = original_scene.visual.vertex_colors.copy()
else:
colors = np.tile([200, 200, 200, 255], (len(original_scene.vertices), 1))
colors = self._normalize_colors(colors)
all_colors.append(colors)
original_point_count = len(original_scene.vertices)
processing_log.append(f"完全保持原始几何体: {original_point_count:,} 个点")
# 添加包围盒线框点云
processing_log.append(f"原始模型结构完全保留: {original_point_count:,} 个点,所有变换矩阵和朝向不变")
# 添加包围盒线框点云到场景
if add_bounding_box_visualization:
box_vertices, box_colors = self._create_bounding_box_pointcloud(
extents, center, bounds_type, wireframe_density, enhance_visibility, processing_log
)
if len(box_vertices) > 0:
all_vertices.append(box_vertices)
all_colors.append(box_colors)
# 创建包围盒点云并添加到场景
bounding_box_pointcloud = trimesh.PointCloud(vertices=box_vertices, colors=box_colors)
visualization_scene.add_geometry(bounding_box_pointcloud, node_name="bounding_box_visualization")
processing_log.append(f"包围盒线框: {len(box_vertices):,} 个点")
# 添加坐标轴点云
# 添加坐标轴点云到场景
if add_coordinate_axes:
axes_vertices, axes_colors = self._create_coordinate_axes_pointcloud(
extents, center, wireframe_density, processing_log
)
if len(axes_vertices) > 0:
all_vertices.append(axes_vertices)
all_colors.append(axes_colors)
# 创建坐标轴点云并添加到场景
coordinate_axes_pointcloud = trimesh.PointCloud(vertices=axes_vertices, colors=axes_colors)
visualization_scene.add_geometry(coordinate_axes_pointcloud, node_name="coordinate_axes")
processing_log.append(f"坐标轴: {len(axes_vertices):,} 个点")
# 合并所有点云
final_vertices = np.vstack(all_vertices)
final_colors = np.vstack(all_colors)
# 统计总点数
total_visualization_points = original_point_count
box_point_count = 0
axes_point_count = 0
processing_log.append(f"总点数: {len(final_vertices):,} 个点")
if add_bounding_box_visualization:
box_point_count = len(box_vertices) if 'box_vertices' in locals() and len(box_vertices) > 0 else 0
total_visualization_points += box_point_count
if add_coordinate_axes:
axes_point_count = len(axes_vertices) if 'axes_vertices' in locals() and len(axes_vertices) > 0 else 0
total_visualization_points += axes_point_count
processing_log.append(f"总点数: {total_visualization_points:,} 个点")
# 生成输出路径
output_path = self._generate_output_path(output_filename)
# 创建trimesh点云对象
visualization_pointcloud = trimesh.PointCloud(
vertices=final_vertices,
colors=final_colors
)
# 保存为GLB文件
visualization_pointcloud.export(output_path)
# 保存场景,完全保持原始模型的结构和朝向
visualization_scene.export(output_path)
processing_log.append(f"可视化点云已保存: {output_path}")
return output_path
@@ -948,7 +1015,7 @@ class GLBPointCloudBounds:
class GLBPointCloudOriginAdjuster:
"""GLB点云原点调整器 - 重新设置点云的原点位置并输出变换信息"""
"""GLB点云原点调整计算器 - 计算原点调整信息并生成带坐标轴的预览文件(原模型数据保持不变)"""
@classmethod
def INPUT_TYPES(cls):
@@ -956,7 +1023,7 @@ class GLBPointCloudOriginAdjuster:
"required": {
"glb_file_path": ("STRING", {
"default": "",
"tooltip": "GLB点云文件路径:输入需要调整原点的GLB格式点云文件"
"tooltip": "GLB点云文件路径:输入需要调整原点的GLB格式点云文件。注意:此节点在原模型基础上添加坐标轴预览,原模型数据保持不变"
}),
},
"optional": {
@@ -992,7 +1059,7 @@ class GLBPointCloudOriginAdjuster:
"transform_info",
)
OUTPUT_TOOLTIPS = [
"调整后的GLB文件完整路径",
"带预览的GLB文件路径 - 包含原始点云+坐标轴预览的完整点云文件",
"纯净的position信息JSON: {\"position\": [x, y, z]} - 仅包含位置信息,可直接用于UE等引擎",
]
OUTPUT_NODE = True
@@ -1042,18 +1109,29 @@ class GLBPointCloudOriginAdjuster:
processing_log.append("正在加载GLB文件...")
scene = trimesh.load(input_path)
# 收集所有几何体和点云
# 收集所有几何体和点云,考虑变换矩阵
geometries_to_transform = []
all_vertices = []
total_points = 0
if isinstance(scene, trimesh.Scene):
for name, geometry in scene.geometry.items():
geometries_to_transform.append((name, geometry))
if hasattr(geometry, 'vertices') and geometry.vertices is not None:
all_vertices.append(geometry.vertices)
total_points += len(geometry.vertices)
processing_log.append(f"发现几何体: {name}, 顶点数: {len(geometry.vertices)}")
for node_name in scene.graph.nodes:
if node_name in scene.geometry:
geometry = scene.geometry[node_name]
transform_matrix = scene.graph[node_name][0] # 获取变换矩阵
geometries_to_transform.append((node_name, geometry))
if hasattr(geometry, 'vertices') and geometry.vertices is not None:
# 应用变换矩阵获取真实世界坐标
if transform_matrix is not None and not np.allclose(transform_matrix, np.eye(4)):
world_vertices = trimesh.transformations.transform_points(geometry.vertices, transform_matrix)
processing_log.append(f"发现几何体: {node_name}, 顶点数: {len(geometry.vertices)}, 已应用变换矩阵")
else:
world_vertices = geometry.vertices.copy()
processing_log.append(f"发现几何体: {node_name}, 顶点数: {len(geometry.vertices)}, 无变换")
all_vertices.append(world_vertices)
total_points += len(geometry.vertices)
else:
# 单个几何体
geometries_to_transform.append(("main_geometry", scene))
@@ -1067,9 +1145,9 @@ class GLBPointCloudOriginAdjuster:
processing_log.append(f"错误: {error_msg}")
return ("", "")
# 合并所有顶点计算包围盒
# 合并所有顶点计算包围盒(已经是世界坐标)
combined_vertices = np.vstack(all_vertices)
processing_log.append(f"总顶点数: {total_points:,}")
processing_log.append(f"总顶点数: {total_points:,} (已应用变换矩阵)")
# 计算原始包围盒
original_min = np.min(combined_vertices, axis=0)
@@ -1158,19 +1236,63 @@ class GLBPointCloudOriginAdjuster:
processing_log.append(f" 中心点: [{new_center[0]:.6f}, {new_center[1]:.6f}, {new_center[2]:.6f}]")
processing_log.append(f" 尺寸: [{new_size[0]:.6f}, {new_size[1]:.6f}, {new_size[2]:.6f}]")
# 生成输出文件
# 生成带预览的输出文件(原模型数据不变,仅添加坐标轴预览)
output_path = self._generate_output_path(output_filename)
processing_log.append(f"输出文件路径: {output_path}")
# 保存变换后的GLB文件
processing_log.append("正在保存变换后的GLB文件...")
new_scene.export(output_path)
# 创建包含原始点云和坐标轴的预览场景,完全保持原始结构
original_scene = trimesh.load(input_path) # 重新加载原始场景
# 创建预览场景,完全复制原始场景的结构
if isinstance(original_scene, trimesh.Scene):
preview_scene = trimesh.Scene()
# 完全复制原始场景的所有几何体和变换矩阵
for node_name in original_scene.graph.nodes:
if node_name in original_scene.geometry:
geometry = original_scene.geometry[node_name]
transform_matrix = original_scene.graph[node_name][0] # 获取变换矩阵
# 完全复制几何体,保持所有属性
copied_geometry = geometry.copy()
# 添加到预览场景,保持原始的变换矩阵
preview_scene.add_geometry(copied_geometry, node_name=node_name, transform=transform_matrix)
processing_log.append(f"完全保持原始几何体: {node_name}, 变换矩阵和朝向已保留")
else:
# 单个几何体的情况
preview_scene = trimesh.Scene()
preview_scene.add_geometry(original_scene.copy(), node_name="main_geometry")
processing_log.append("完全保持原始几何体: main_geometry, 所有属性已保留")
# 添加坐标轴预览(如果需要)
if add_coordinate_axes:
try:
# 使用原始包围盒来确定坐标轴长度
axis_length = np.max(original_size) * 0.4
# 在计算出的新原点位置生成坐标轴
axes_vertices, axes_colors = self._create_coordinate_axes_pointcloud_at_position(
new_origin, axis_length, wireframe_density, processing_log
)
if len(axes_vertices) > 0:
# 创建坐标轴点云并添加到场景
axes_pointcloud = trimesh.PointCloud(vertices=axes_vertices, colors=axes_colors)
preview_scene.add_geometry(axes_pointcloud, node_name="coordinate_axes_preview")
processing_log.append(f"坐标轴预览: {len(axes_vertices):,} 个点 (显示建议的新原点位置)")
except Exception as e:
processing_log.append(f"坐标轴生成失败: {str(e)}")
# 保存预览文件
processing_log.append("正在保存带预览的GLB文件...")
preview_scene.export(output_path)
if os.path.exists(output_path):
file_size = os.path.getsize(output_path)
processing_log.append(f"GLB文件保存成功,文件大小: {file_size} bytes")
processing_log.append(f"预览GLB文件保存成功,文件大小: {file_size} bytes")
else:
error_msg = "GLB文件保存失败"
error_msg = "预览GLB文件保存失败"
processing_log.append(f"错误: {error_msg}")
return ("", "")
@@ -1184,12 +1306,10 @@ class GLBPointCloudOriginAdjuster:
"position": [float(final_position[0]), float(final_position[1]), float(final_position[2])]
}
processing_log.append("")
processing_log.append(f"变换信息 (单位: {output_units}):")
processing_log.append(f" Position: [{transform_info['position'][0]:.2f}, {transform_info['position'][1]:.2f}, {transform_info['position'][2]:.2f}]")
processing_log.append("GLB点云原点调整完成!")
processing_log.append("原点调整预览生成完成!")
return (
output_path,
@@ -1245,6 +1365,121 @@ class GLBPointCloudOriginAdjuster:
def _create_coordinate_axes_pointcloud_at_position(self, position, axis_length, wireframe_density, processing_log):
"""在指定位置创建坐标轴的点云表示"""
try:
center = np.array(position) # 指定的位置
axis_thickness = axis_length * 0.01 # 坐标轴厚度
axes_points = []
axes_colors = []
# 计算坐标轴密度
axis_line_density = wireframe_density # 使用参数控制密度
axis_thickness_points = max(3, axis_line_density // 15) # 厚度方向的点数
# X轴 - 红色(从指定位置开始)
for i in range(axis_line_density):
t = i / (axis_line_density - 1) if axis_line_density > 1 else 0
base_point = [center[0] + t * axis_length, center[1], center[2]]
# 主轴线
axes_points.append(base_point)
axes_colors.append([255, 0, 0, 255])
# 增加厚度(在YZ平面上添加点)
for j in range(axis_thickness_points):
for k in range(axis_thickness_points):
offset_y = (j - axis_thickness_points//2) * axis_thickness / axis_thickness_points
offset_z = (k - axis_thickness_points//2) * axis_thickness / axis_thickness_points
thick_point = [base_point[0], base_point[1] + offset_y, base_point[2] + offset_z]
axes_points.append(thick_point)
axes_colors.append([255, 0, 0, 255])
# X轴箭头头部
arrow_length = axis_length * 0.1
arrow_base = axis_length * 0.9
for i in range(axis_line_density // 2):
t = i / (axis_line_density // 2 - 1) if axis_line_density > 2 else 0
arrow_x = center[0] + arrow_base + t * arrow_length
arrow_offset = (1 - t) * axis_thickness * 2
axes_points.append([arrow_x, center[1] + arrow_offset, center[2]])
axes_points.append([arrow_x, center[1] - arrow_offset, center[2]])
axes_points.append([arrow_x, center[1], center[2] + arrow_offset])
axes_points.append([arrow_x, center[1], center[2] - arrow_offset])
axes_colors.extend([[255, 0, 0, 255]] * 4)
# Y轴 - 绿色(从指定位置开始)
for i in range(axis_line_density):
t = i / (axis_line_density - 1) if axis_line_density > 1 else 0
base_point = [center[0], center[1] + t * axis_length, center[2]]
# 主轴线
axes_points.append(base_point)
axes_colors.append([0, 255, 0, 255])
# 增加厚度(在XZ平面上添加点)
for j in range(axis_thickness_points):
for k in range(axis_thickness_points):
offset_x = (j - axis_thickness_points//2) * axis_thickness / axis_thickness_points
offset_z = (k - axis_thickness_points//2) * axis_thickness / axis_thickness_points
thick_point = [base_point[0] + offset_x, base_point[1], base_point[2] + offset_z]
axes_points.append(thick_point)
axes_colors.append([0, 255, 0, 255])
# Y轴箭头头部
for i in range(axis_line_density // 2):
t = i / (axis_line_density // 2 - 1) if axis_line_density > 2 else 0
arrow_y = center[1] + arrow_base + t * arrow_length
arrow_offset = (1 - t) * axis_thickness * 2
axes_points.append([center[0] + arrow_offset, arrow_y, center[2]])
axes_points.append([center[0] - arrow_offset, arrow_y, center[2]])
axes_points.append([center[0], arrow_y, center[2] + arrow_offset])
axes_points.append([center[0], arrow_y, center[2] - arrow_offset])
axes_colors.extend([[0, 255, 0, 255]] * 4)
# Z轴 - 蓝色(从指定位置开始)
for i in range(axis_line_density):
t = i / (axis_line_density - 1) if axis_line_density > 1 else 0
base_point = [center[0], center[1], center[2] + t * axis_length]
# 主轴线
axes_points.append(base_point)
axes_colors.append([0, 0, 255, 255])
# 增加厚度(在XY平面上添加点)
for j in range(axis_thickness_points):
for k in range(axis_thickness_points):
offset_x = (j - axis_thickness_points//2) * axis_thickness / axis_thickness_points
offset_y = (k - axis_thickness_points//2) * axis_thickness / axis_thickness_points
thick_point = [base_point[0] + offset_x, base_point[1] + offset_y, base_point[2]]
axes_points.append(thick_point)
axes_colors.append([0, 0, 255, 255])
# Z轴箭头头部
for i in range(axis_line_density // 2):
t = i / (axis_line_density // 2 - 1) if axis_line_density > 2 else 0
arrow_z = center[2] + arrow_base + t * arrow_length
arrow_offset = (1 - t) * axis_thickness * 2
axes_points.append([center[0] + arrow_offset, center[1], arrow_z])
axes_points.append([center[0] - arrow_offset, center[1], arrow_z])
axes_points.append([center[0], center[1] + arrow_offset, arrow_z])
axes_points.append([center[0], center[1] - arrow_offset, arrow_z])
axes_colors.extend([[0, 0, 255, 255]] * 4)
axes_vertices = np.array(axes_points)
axes_colors_array = np.array(axes_colors)
processing_log.append(f"坐标轴生成: {len(axes_vertices):,} 个点 (长度={axis_length:.3f}, 密度={wireframe_density}, 位置=[{center[0]:.3f}, {center[1]:.3f}, {center[2]:.3f}])")
return axes_vertices, axes_colors_array
except Exception as e:
processing_log.append(f"创建坐标轴点云失败: {str(e)}")
return np.array([]), np.array([])
def _create_coordinate_axes_pointcloud_at_origin(self, axis_length, wireframe_density, processing_log):
"""在原点(0,0,0)创建坐标轴的点云表示"""
try: