阿斯蒂芬
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,180 @@
|
||||
import os
|
||||
|
||||
def process_obj_file(input_file, output_file):
|
||||
"""
|
||||
处理OBJ文件,使用顶点x,y坐标映射纹理UV坐标,忽略z值,同时保持原有文件结构和注释顺序
|
||||
|
||||
参数:
|
||||
input_file: 输入OBJ文件路径
|
||||
output_file: 输出OBJ文件路径
|
||||
"""
|
||||
# 检查输入文件是否存在
|
||||
if not os.path.exists(input_file):
|
||||
print(f"错误: 输入文件 {input_file} 不存在")
|
||||
return False
|
||||
|
||||
try:
|
||||
with open(input_file, 'r', encoding='utf-8') as f_in:
|
||||
lines = f_in.readlines()
|
||||
|
||||
# 提取顶点坐标并计算UV坐标
|
||||
vertices = [] # 存储顶点坐标 (x, y)
|
||||
vertex_lines = [] # 存储原始的顶点行
|
||||
|
||||
for line in lines:
|
||||
stripped_line = line.strip()
|
||||
if stripped_line.startswith('v ') and not stripped_line.startswith('vt ') and not stripped_line.startswith('vn '):
|
||||
parts = stripped_line.split()
|
||||
if len(parts) >= 3: # 至少要有v x y
|
||||
try:
|
||||
x = float(parts[1])
|
||||
y = float(parts[2])
|
||||
vertices.append((x, y))
|
||||
vertex_lines.append(line.rstrip())
|
||||
except ValueError:
|
||||
# 如果解析失败,使用默认值
|
||||
vertices.append((0.0, 0.0))
|
||||
vertex_lines.append(line.rstrip())
|
||||
|
||||
# 计算UV坐标的边界范围
|
||||
if vertices:
|
||||
x_coords = [v[0] for v in vertices]
|
||||
y_coords = [v[1] for v in vertices]
|
||||
min_x, max_x = min(x_coords), max(x_coords)
|
||||
min_y, max_y = min(y_coords), max(y_coords)
|
||||
|
||||
# 避免除零错误
|
||||
x_range = max_x - min_x if max_x != min_x else 1.0
|
||||
y_range = max_y - min_y if max_y != min_y else 1.0
|
||||
|
||||
# 为每个顶点生成UV坐标(基于x,y坐标映射到0-1范围)
|
||||
uv_coords = []
|
||||
for x, y in vertices:
|
||||
# 将x,y坐标归一化到0-1范围
|
||||
u = (x - min_x) / x_range
|
||||
v = (y - min_y) / y_range
|
||||
uv_coords.append(f"vt {u:.6f} {v:.6f}")
|
||||
else:
|
||||
uv_coords = []
|
||||
|
||||
# 处理每一行,保持原有顺序
|
||||
processed_lines = []
|
||||
current_vertex_index = 0
|
||||
face_count = 0
|
||||
|
||||
for line in lines:
|
||||
original_line = line.rstrip() # 去除右侧空白,保持左侧缩进
|
||||
|
||||
# 如果是顶点数据,保持原样
|
||||
if original_line.startswith('v ') and not original_line.startswith('vt ') and not original_line.startswith('vn '):
|
||||
processed_lines.append(original_line)
|
||||
current_vertex_index += 1
|
||||
|
||||
# 如果是面数据,为每个顶点引用对应的纹理坐标
|
||||
elif original_line.startswith('f '):
|
||||
face_parts = original_line.split()
|
||||
if len(face_parts) >= 4: # 至少应该有 "f" 和三个顶点
|
||||
# 重建面数据,为每个顶点添加对应的纹理坐标索引
|
||||
new_face_parts = ['f']
|
||||
vertex_indices = []
|
||||
|
||||
# 首先提取所有顶点索引
|
||||
for part in face_parts[1:]:
|
||||
if '//' in part: # 格式: v//vn
|
||||
v_index, vn_index = part.split('//')
|
||||
vertex_indices.append(int(v_index))
|
||||
elif '/' in part: # 格式: v/vt/vn 或 v/vt
|
||||
parts = part.split('/')
|
||||
vertex_indices.append(int(parts[0]))
|
||||
else: # 只有顶点索引
|
||||
vertex_indices.append(int(part))
|
||||
|
||||
# 为每个顶点构建新的面数据
|
||||
for j, part in enumerate(face_parts[1:]):
|
||||
vertex_index = vertex_indices[j]
|
||||
|
||||
if '//' in part: # 格式: v//vn
|
||||
v_index, vn_index = part.split('//')
|
||||
# 使用顶点索引作为纹理坐标索引(因为是一一对应的)
|
||||
new_part = f"{v_index}/{vertex_index}//{vn_index}"
|
||||
elif '/' in part: # 格式: v/vt/vn 或 v/vt
|
||||
parts = part.split('/')
|
||||
if len(parts) == 2: # v/vt
|
||||
new_part = f"{parts[0]}/{vertex_index}"
|
||||
else: # v/vt/vn
|
||||
new_part = f"{parts[0]}/{vertex_index}/{parts[2]}"
|
||||
else: # 只有顶点索引
|
||||
new_part = f"{part}/{vertex_index}"
|
||||
|
||||
new_face_parts.append(new_part)
|
||||
|
||||
processed_lines.append(' '.join(new_face_parts))
|
||||
face_count += 1
|
||||
else:
|
||||
processed_lines.append(original_line)
|
||||
else:
|
||||
processed_lines.append(original_line)
|
||||
|
||||
# 在顶点数据之后插入纹理坐标定义
|
||||
output_lines = []
|
||||
vertices_ended = False
|
||||
uv_inserted = False
|
||||
vertex_count = 0
|
||||
|
||||
for i, line in enumerate(processed_lines):
|
||||
output_lines.append(line)
|
||||
|
||||
# 统计顶点数量
|
||||
if line.startswith('v ') and not line.startswith('vt ') and not line.startswith('vn '):
|
||||
vertex_count += 1
|
||||
|
||||
# 检测顶点数据块的结束(当遇到非顶点数据时)
|
||||
if not vertices_ended and line.startswith('v ') and not line.startswith('vt ') and not line.startswith('vn '):
|
||||
# 当前行是顶点数据,继续
|
||||
pass
|
||||
elif not vertices_ended and i > 0 and vertex_count > 0:
|
||||
# 当前行不是顶点数据,且我们已经处理过顶点数据
|
||||
# 这意味着顶点数据块已经结束
|
||||
vertices_ended = True
|
||||
|
||||
# 在顶点数据块结束后插入纹理坐标
|
||||
if not uv_inserted and uv_coords:
|
||||
output_lines.append("") # 空行分隔
|
||||
output_lines.append("# 添加的纹理坐标 (基于顶点x,y坐标映射,忽略z值)")
|
||||
output_lines.append(f"# UV坐标范围: x[{min_x:.6f}-{max_x:.6f}] -> u[0-1], y[{min_y:.6f}-{max_y:.6f}] -> v[0-1]")
|
||||
for uv in uv_coords:
|
||||
output_lines.append(uv)
|
||||
uv_inserted = True
|
||||
|
||||
# 如果文件中顶点数据在最后,在最后插入UV坐标
|
||||
if not uv_inserted and uv_coords:
|
||||
output_lines.append("") # 空行分隔
|
||||
output_lines.append("# 添加的纹理坐标 (基于顶点x,y坐标映射,忽略z值)")
|
||||
output_lines.append(f"# UV坐标范围: x[{min_x:.6f}-{max_x:.6f}] -> u[0-1], y[{min_y:.6f}-{max_y:.6f}] -> v[0-1]")
|
||||
for uv in uv_coords:
|
||||
output_lines.append(uv)
|
||||
|
||||
# 写入输出文件
|
||||
with open(output_file, 'w', encoding='utf-8') as f_out:
|
||||
for line in output_lines:
|
||||
f_out.write(line + '\n')
|
||||
|
||||
print(f"成功处理文件: {input_file} -> {output_file}")
|
||||
print(f"顶点数量: {len(vertices)}")
|
||||
print(f"处理面数量: {face_count}")
|
||||
print(f"生成的纹理坐标数量: {len(uv_coords)}")
|
||||
print(f"顶点X坐标范围: {min_x:.6f} 到 {max_x:.6f}")
|
||||
print(f"顶点Y坐标范围: {min_y:.6f} 到 {max_y:.6f}")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"处理文件时出错: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
input_file = "face.obj" # 默认输入文件
|
||||
output_file = "face_with_uv.obj" # 默认输出文件
|
||||
process_obj_file(input_file, output_file)
|
||||
Reference in New Issue
Block a user