如何用Python合并多个.obj文件?顶点法线处理遇问题
合并带顶点法线的OBJ文件解决方案
核心问题分析
你之前只调整了面的顶点编号,但忽略了顶点法线(vn)的编号偏移——每个OBJ文件的顶点和法线都是独立从1开始计数的,合并时第二个文件的面里的法线编号必须加上第一个文件的法线总数,顶点编号加上第一个文件的顶点总数,否则面会错误引用不属于它的法线/顶点。
具体实现步骤
- 逐个读取OBJ文件,拆分出顶点(v)、顶点法线(vn)、面(f)三类数据,同时记录每个文件的顶点数和法线数。
- 合并阶段:先拼接所有文件的顶点数据,再拼接所有法线数据。
- 调整面的编号:对每个文件的面,将其中的顶点编号累加前面所有文件的顶点总数,法线编号累加前面所有文件的法线总数。
- 将合并后的所有数据写入新的OBJ文件。
Python代码示例
def merge_obj_files(input_files, output_file): merged_v = [] merged_vn = [] merged_f = [] total_v_count = 0 total_vn_count = 0 for file_path in input_files: v = [] vn = [] f = [] with open(file_path, 'r') as f_obj: for line in f_obj: line = line.strip() if not line: continue parts = line.split() if parts[0] == 'v': v.append(line) elif parts[0] == 'vn': vn.append(line) elif parts[0] == 'f': f.append(parts) # 合并顶点和法线 merged_v.extend(v) merged_vn.extend(vn) # 处理面的编号偏移 for face_parts in f: new_face = ['f'] for elem in face_parts[1:]: # 拆分顶点//法线的格式 v_id, _, vn_id = elem.split('//') new_v_id = str(int(v_id) + total_v_count) new_vn_id = str(int(vn_id) + total_vn_count) new_elem = f"{new_v_id}//{new_vn_id}" new_face.append(new_elem) merged_f.append(' '.join(new_face)) # 更新累计的顶点和法线数量 total_v_count += len(v) total_vn_count += len(vn) # 写入合并后的文件 with open(output_file, 'w') as out_obj: out_obj.write('\n'.join(merged_v) + '\n\n') out_obj.write('\n'.join(merged_vn) + '\n\n') out_obj.write('\n'.join(merged_f)) # 使用示例 if __name__ == "__main__": input_files = ["File1.obj", "File2.obj"] merge_obj_files(input_files, "merged.obj")
验证说明
运行代码后,合并后的OBJ文件中:
- 顶点是File1的3个顶点 + File2的3个顶点,共6个。
- 法线是File1的3个法线 + File2的3个法线,共6个。
- File2的面里的顶点编号会从原来的216、182等变为216+3=219、182+3=185,法线编号从216变为216+3=219,以此类推,确保面正确引用对应的顶点和法线。
内容的提问来源于stack exchange,提问作者Mass17
相关产品推荐
相关产品推荐

