使用python实现obj模型的两种模式预览(片面图与附加纹理的3d预览)
用
numpy
处理顶点数据,并通过matplotlib
的 3D 功能可视化模型,使用Poly3DCollection
绘制三角面片。
首先,我们需要知道,obj文件中都有些什么信息
这是我从网上找的一个关于椅子的3d.obj文件
model.obj就是我们主要的文件了
obj文件中,包括(顶点坐标,面,纹理的uv映射和法线向量)这些信息要素
v代表的就是模型的顶点坐标
f代表的就是模型的面
vt代表的是纹理的uv映射
vn代表法线向量
一:解析文件
-
#解析obj文件中的信息,提取点面信息 vertices = [] faces = [] with open(file_path, 'r') as f: for line in f: if line.startswith('v '): parts = line.strip().split() vertex = list(map(float, parts[1:4])) vertices.append(vertex) elif line.startswith('f '): parts = line.strip().split() face = [] for part in parts[1:]: vertex_index = part.split('/')[0] face.append(int(vertex_index) - 1) faces.append(face) return np.array(vertices), faces
二:创建画布与坐标系
#创建画布与坐标系
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
三:生成面片信息
#生成面片数据
mesh = []
for face in faces:
polygon = vertices[face, :]
mesh.append(polygon)
四:绘制三维的面片
#绘制三维的面片
ax.add_collection3d(Poly3DCollection(
mesh,
facecolors='cyan', #面片颜色
linewidths=0.5, #边线宽度
edgecolors='black', #边线颜色
alpha=0.4 #透明度
))
下面是代码:#生成的是面片的模型图
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import os
import numpy as np
def parse_obj(file_path):
if not os.path.exists(obj_path):
print(f"错误:文件不存在 - {obj_path}")
exit()
else:
print("文件存在,继续解析...")
#解析obj文件中的信息,提取点面信息
vertices = []
faces = []
with open(file_path, 'r') as f:
for line in f:
if line.startswith('v '):
parts = line.strip().split()
vertex = list(map(float, parts[1:4]))
vertices.append(vertex)
elif line.startswith('f '):
parts = line.strip().split()
face = []
for part in parts[1:]:
vertex_index = part.split('/')[0]
face.append(int(vertex_index) - 1)
faces.append(face)
return np.array(vertices), faces
def show_obj(vertices, faces):
#创建画布与坐标系
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#生成面片数据
mesh = []
for face in faces:
polygon = vertices[face, :]
mesh.append(polygon)
#绘制三维的面片
ax.add_collection3d(Poly3DCollection(
mesh,
facecolors='cyan', #面片颜色
linewidths=0.5, #边线宽度
edgecolors='black', #边线颜色
alpha=0.4 #透明度
))
#设置坐标轴的范围
min_vals = vertices.min(axis=0)
max_vals = vertices.max(axis=0)
ax.auto_scale_xyz([min_vals[0], max_vals[0]],
[min_vals[1], max_vals[1]],
[min_vals[2], max_vals[2]])
#坐标标签
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
if __name__ == "__main__":
obj_path = r"model.obj"
vertices, faces = parse_obj(obj_path)
show_obj(vertices, faces)
下面是生成带纹理的模型
mport trimesh
def load_and_render_obj_with_texture(obj_path):
#加载带纹理的OBJ模型并渲染
# 加载模型(自动解析纹理和材质)
mesh = trimesh.load(obj_path, force='mesh')
# 检查是否成功加载纹理
if mesh.visual.kind != 'texture':
print("警告:未找到纹理信息,将使用默认颜色渲染")
else:
print("纹理信息已加载")
# 打印模型基本信息
print(f"顶点数: {len(mesh.vertices)}")
print(f"面数: {len(mesh.faces)}")
print(f"纹理坐标数: {len(mesh.visual.uv)}")
mesh.show()
if __name__ == "__main__":
obj_path = r"model.obj"
load_and_render_obj_with_texture(obj_path)
纹理信息已加载
顶点数: 7304
面数: 4574
纹理坐标数: 7304
下面是完整代码:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import os
import trimesh
import numpy as np
def parse_obj(file_path):
if not os.path.exists(obj_path):
print(f"错误:文件不存在 - {obj_path}")
exit()
else:
print("文件存在,继续解析...")
#解析obj文件中的信息,提取店面信息
vertices = []
faces = []
with open(file_path, 'r') as f:
for line in f:
if line.startswith('v '):
parts = line.strip().split()
vertex = list(map(float, parts[1:4]))
vertices.append(vertex)
elif line.startswith('f '):
parts = line.strip().split()
face = []
for part in parts[1:]:
vertex_index = part.split('/')[0]
face.append(int(vertex_index) - 1)
faces.append(face)
return np.array(vertices), faces
def show_obj(vertices, faces):
#创建画布与坐标系
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#生成面片数据
mesh = []
for face in faces:
polygon = vertices[face, :]
mesh.append(polygon)
#绘制三维的面片
ax.add_collection3d(Poly3DCollection(
mesh,
facecolors='cyan', #面片颜色
linewidths=0.5, #边线宽度
edgecolors='black', #边线颜色
alpha=0.4 #透明度
))
#设置坐标轴的范围
min_vals = vertices.min(axis=0)
max_vals = vertices.max(axis=0)
ax.auto_scale_xyz([min_vals[0], max_vals[0]],
[min_vals[1], max_vals[1]],
[min_vals[2], max_vals[2]])
#坐标标签
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
def load_and_render_obj_with_texture(obj_path):
#加载带纹理的OBJ模型并渲染
# 加载模型(自动解析纹理和材质)
mesh = trimesh.load(obj_path, force='mesh')
# 检查是否成功加载纹理
if mesh.visual.kind != 'texture':
print("警告:未找到纹理信息,将使用默认颜色渲染")
else:
print("纹理信息已加载")
# 打印模型基本信息
print(f"顶点数: {len(mesh.vertices)}")
print(f"面数: {len(mesh.faces)}")
print(f"纹理坐标数: {len(mesh.visual.uv)}")
mesh.show()
if __name__ == "__main__":
obj_path = r"model.obj"
vertices, faces = parse_obj(obj_path)
show_obj(vertices, faces)
load_and_render_obj_with_texture(obj_path)
文件存在,继续解析...
纹理信息已加载
顶点数: 7304
面数: 4574
纹理坐标数: 7304
模型来源https://free3d.io/
ps:第一次发文章,不便之处多多包涵