161 lines
6.7 KiB
Python
161 lines
6.7 KiB
Python
import numpy as np
|
|
|
|
def read_obj_vertices(obj_file_path):
|
|
"""读取OBJ文件中的顶点数据"""
|
|
vertices = []
|
|
with open(obj_file_path, 'r') as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if line.startswith('v ') and not line.startswith('vt ') and not line.startswith('vn '):
|
|
parts = line.split()
|
|
if len(parts) >= 4:
|
|
# 提取顶点坐标,转换为浮点数
|
|
vertex = [float(parts[1]), float(parts[2]), float(parts[3])]
|
|
vertices.append(vertex)
|
|
return np.array(vertices)
|
|
|
|
def find_vertex_mapping(original_vertices, modified_vertices, tolerance=1e-4):
|
|
"""
|
|
找到修改后顶点在原始顶点中的索引映射
|
|
使用严格的数值匹配,匹配失败或重复匹配都会报错
|
|
"""
|
|
mapping = []
|
|
used_indices = set()
|
|
|
|
for i, mod_vertex in enumerate(modified_vertices):
|
|
matches = []
|
|
|
|
# 查找所有在容差范围内的匹配顶点
|
|
for j, orig_vertex in enumerate(original_vertices):
|
|
if np.allclose(mod_vertex, orig_vertex, atol=tolerance):
|
|
matches.append(j)
|
|
|
|
# 检查匹配结果
|
|
if len(matches) == 0:
|
|
# 没有找到匹配
|
|
print(f"错误: 无法为修改后顶点 {i} ({mod_vertex}) 找到匹配的原始顶点")
|
|
print(f" 最近的原始顶点:")
|
|
# 找到最近的几个顶点供参考
|
|
distances = []
|
|
for j, orig_vertex in enumerate(original_vertices):
|
|
dist = np.linalg.norm(mod_vertex - orig_vertex)
|
|
distances.append((dist, j, orig_vertex))
|
|
distances.sort()
|
|
for dist, j, vertex in distances[:3]: # 显示最近的3个
|
|
print(f" 索引 {j}: {vertex}, 距离: {dist:.6f}")
|
|
raise ValueError(f"顶点 {i} 匹配失败")
|
|
|
|
elif len(matches) > 1:
|
|
# 找到多个匹配
|
|
print(f"错误: 为修改后顶点 {i} ({mod_vertex}) 找到多个匹配的原始顶点:")
|
|
for match_idx in matches:
|
|
print(f" 原始顶点索引 {match_idx}: {original_vertices[match_idx]}")
|
|
raise ValueError(f"顶点 {i} 匹配到多个原始顶点")
|
|
|
|
else:
|
|
# 找到一个匹配
|
|
match_idx = matches[0]
|
|
if match_idx in used_indices:
|
|
print(f"错误: 原始顶点 {match_idx} 已经被多个修改后顶点匹配")
|
|
print(f" 当前修改后顶点 {i}: {mod_vertex}")
|
|
# 找出哪个修改后顶点已经匹配了这个原始顶点
|
|
for k, mapped_idx in enumerate(mapping):
|
|
if mapped_idx == match_idx:
|
|
print(f" 已经被修改后顶点 {k}: {modified_vertices[k]} 匹配")
|
|
raise ValueError(f"原始顶点 {match_idx} 被重复匹配")
|
|
|
|
mapping.append(match_idx)
|
|
used_indices.add(match_idx)
|
|
|
|
return mapping
|
|
|
|
def validate_mapping_completeness(mapping, original_vertices, modified_vertices):
|
|
"""验证映射的完整性"""
|
|
print("\n验证映射完整性...")
|
|
|
|
# 检查是否有未匹配的原始顶点
|
|
all_original_indices = set(range(len(original_vertices)))
|
|
used_original_indices = set(mapping)
|
|
unused_original_indices = all_original_indices - used_original_indices
|
|
|
|
if unused_original_indices:
|
|
print(f"警告: 有 {len(unused_original_indices)} 个原始顶点未被使用:")
|
|
for idx in list(unused_original_indices)[:5]: # 只显示前5个
|
|
print(f" 原始顶点 {idx}: {original_vertices[idx]}")
|
|
if len(unused_original_indices) > 5:
|
|
print(f" ... 还有 {len(unused_original_indices) - 5} 个")
|
|
|
|
# 检查顶点数量是否一致
|
|
if len(modified_vertices) != len(original_vertices):
|
|
print(f"警告: 顶点数量不一致 - 原始: {len(original_vertices)}, 修改后: {len(modified_vertices)}")
|
|
|
|
return len(unused_original_indices) == 0
|
|
|
|
def generate_header_file(mapping, output_file="map.h"):
|
|
"""生成C++头文件"""
|
|
with open(output_file, 'w') as f:
|
|
f.write("#ifndef VERTEX_MAP_H\n")
|
|
f.write("#define VERTEX_MAP_H\n\n")
|
|
f.write("// 顶点索引映射表\n")
|
|
f.write("// 用于将face_picture_3dmax.obj的顶点索引映射到face_picture.obj的顶点索引\n")
|
|
f.write("// 生成说明: modified_vertex_index -> original_vertex_index\n")
|
|
f.write("// 注意: 这个映射是严格的一对一匹配,匹配容差为1e-4\n")
|
|
f.write(f"const int indexMap[{len(mapping)}] = {{\n")
|
|
|
|
# 每行输出10个元素
|
|
for i in range(0, len(mapping), 10):
|
|
line_indices = mapping[i:i+10]
|
|
line = " " + ", ".join(f"{idx:3d}" for idx in line_indices)
|
|
if i + 10 < len(mapping):
|
|
line += ","
|
|
f.write(line + "\n")
|
|
|
|
f.write("};\n\n")
|
|
f.write("#endif // VERTEX_MAP_H\n")
|
|
|
|
def main():
|
|
# 文件路径
|
|
original_obj = "../assets/face_picture.obj"
|
|
modified_obj = "../assets/face_picture_3dmax.obj"
|
|
output_header = "map.h"
|
|
|
|
# 匹配容差 - 根据你的数据精度调整这个值
|
|
tolerance = 1e-4
|
|
|
|
print("正在读取OBJ文件...")
|
|
|
|
try:
|
|
# 读取顶点数据
|
|
original_vertices = read_obj_vertices(original_obj)
|
|
modified_vertices = read_obj_vertices(modified_obj)
|
|
|
|
print(f"原始文件顶点数: {len(original_vertices)}")
|
|
print(f"修改文件顶点数: {len(modified_vertices)}")
|
|
print(f"匹配容差: {tolerance}")
|
|
|
|
# 找到顶点映射
|
|
print("正在严格匹配顶点...")
|
|
mapping = find_vertex_mapping(original_vertices, modified_vertices, tolerance)
|
|
|
|
# 验证完整性
|
|
is_complete = validate_mapping_completeness(mapping, original_vertices, modified_vertices)
|
|
|
|
if is_complete:
|
|
print("✓ 所有原始顶点都被正确使用")
|
|
else:
|
|
print("⚠ 部分原始顶点未被使用")
|
|
|
|
print(f"✓ 成功匹配所有 {len(mapping)} 个顶点")
|
|
|
|
# 生成头文件
|
|
print(f"生成头文件: {output_header}")
|
|
generate_header_file(mapping, output_header)
|
|
|
|
print("\n完成!映射文件已生成。")
|
|
|
|
except Exception as e:
|
|
print(f"\n❌ 错误: {e}")
|
|
print("映射生成失败,请检查数据或调整匹配容差")
|
|
|
|
if __name__ == "__main__":
|
|
main() |