Python + OpenGL 如何加载.obj三维模型文件并利用三视图投影法获取六张二维视图图片
Python + OpenGL 如何加载.obj三维模型文件并利用三视图投影法获取六张二维视图图片
9 回复
obj 模型存储的应该是是模型三角面信息,理论上讲,不需要 opengl,直接使用三角面坐标进行矩阵运算然后忽略一个坐标纬度,然后在图片里面绘制就可以了
我来给你一个完整的解决方案。这个需求可以分解为:用PyOpenGL加载.obj文件,然后从六个正交投影方向(前、后、左、右、上、下)渲染模型并保存为图片。
import numpy as np
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import pygame
from pygame.locals import *
from PIL import Image
import io
class OBJLoader:
def __init__(self):
self.vertices = []
self.faces = []
def load(self, filename):
with open(filename, 'r') as f:
for line in f:
if line.startswith('v '):
vertex = list(map(float, line.strip().split()[1:4]))
self.vertices.append(vertex)
elif line.startswith('f '):
face = []
for v in line.strip().split()[1:]:
face.append(int(v.split('/')[0]) - 1)
self.faces.append(face)
# 计算模型边界用于调整视图
vertices_array = np.array(self.vertices)
self.min_coords = vertices_array.min(axis=0)
self.max_coords = vertices_array.max(axis=0)
self.center = (self.min_coords + self.max_coords) / 2
self.size = np.max(self.max_coords - self.min_coords) * 1.2
print(f"Loaded {len(self.vertices)} vertices, {len(self.faces)} faces")
class ModelRenderer:
def __init__(self, obj_file, output_size=(512, 512)):
self.obj = OBJLoader()
self.obj.load(obj_file)
self.output_size = output_size
# 初始化Pygame和OpenGL
pygame.init()
self.screen = pygame.display.set_mode(output_size, DOUBLEBUF | OPENGL)
glEnable(GL_DEPTH_TEST)
glClearColor(1.0, 1.0, 1.0, 1.0) # 白色背景
def setup_ortho_projection(self):
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
size = self.obj.size
glOrtho(-size, size, -size, size, -size*2, size*2)
glMatrixMode(GL_MODELVIEW)
def render_view(self, view_name):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
# 根据视图名称设置相机位置
if view_name == 'front':
gluLookAt(0, 0, self.obj.size, 0, 0, 0, 0, 1, 0)
elif view_name == 'back':
gluLookAt(0, 0, -self.obj.size, 0, 0, 0, 0, 1, 0)
elif view_name == 'left':
gluLookAt(-self.obj.size, 0, 0, 0, 0, 0, 0, 1, 0)
elif view_name == 'right':
gluLookAt(self.obj.size, 0, 0, 0, 0, 0, 0, 1, 0)
elif view_name == 'top':
gluLookAt(0, self.obj.size, 0, 0, 0, 0, 0, 0, -1)
elif view_name == 'bottom':
gluLookAt(0, -self.obj.size, 0, 0, 0, 0, 0, 0, 1)
# 绘制模型
glColor3f(0.2, 0.2, 0.2) # 灰色模型
glBegin(GL_TRIANGLES)
for face in self.obj.faces:
for vertex_idx in face:
vertex = self.obj.vertices[vertex_idx]
glVertex3fv(vertex)
glEnd()
# 读取像素数据
glPixelStorei(GL_PACK_ALIGNMENT, 1)
data = glReadPixels(0, 0, self.output_size[0], self.output_size[1],
GL_RGB, GL_UNSIGNED_BYTE)
# 转换为PIL Image
image = Image.frombytes("RGB", self.output_size, data)
image = image.transpose(Image.FLIP_TOP_BOTTOM) # OpenGL坐标翻转
return image
def generate_all_views(self):
views = ['front', 'back', 'left', 'right', 'top', 'bottom']
images = {}
for view in views:
print(f"Rendering {view} view...")
self.setup_ortho_projection()
img = self.render_view(view)
images[view] = img
return images
def save_views(self, images, output_dir="output"):
import os
os.makedirs(output_dir, exist_ok=True)
for view_name, img in images.items():
filename = f"{output_dir}/{view_name}_view.png"
img.save(filename)
print(f"Saved: {filename}")
# 使用示例
if __name__ == "__main__":
# 替换为你的.obj文件路径
obj_file = "your_model.obj"
renderer = ModelRenderer(obj_file)
images = renderer.generate_all_views()
renderer.save_views(images)
print("六视图生成完成!")
核心要点:
- OBJ加载:解析.obj文件中的顶点和面数据
- 正交投影:使用
glOrtho确保无透视变形 - 六视图相机:通过
gluLookAt设置六个方向的观察矩阵 - 图像保存:用
glReadPixels捕获OpenGL缓冲区并保存为PNG
依赖安装:
pip install PyOpenGL PyOpenGL-accelerate pygame pillow numpy
注意事项:
- 确保.obj文件使用三角面片(f v1 v2 v3格式)
- 模型尺寸过小时适当调整
glOrtho参数 - 复杂模型可能需要法线数据用于光照(这里简化了)
这个方案直接生成标准的工程三视图投影,适合机械零件、建筑模型等需要正交投影的场合。
虽然我没做过这方面的,但是投影不就是取与投影方向垂直平面上的最大值,比如 z 轴,那就是 x,y 最大的点,这应该不用重建的吧?
而且六张实际上只有三张的吧?上下投影有什么区别吗?
您有相关的资料吗?谢谢。
只是一个思路,读取 obj 模型里面的坐标信息,obj 格式是公开的,上下左右这些视角可以与 mtrix4*4 矩阵对应,比如左视角可以看成绕着 y 轴旋转 90 度,原坐标和矩阵运算后,去掉坐标 z 纬度,用 xy 纬度在图片里面用像素画出来就可以了
读 obj>matrix4×4 矩阵运算>画图
感谢二位的建议,我考虑下
请教一下您,您解决了三视图投影吗?可以交流一下吗

