Bonjour,
Dans le cadre de developpement de mon moteur 3D en python et opengl je fais face a un probleme tres embetant: Les performances sont tres basses(~ 20 FPS). Le moteur est encore super simple, je en fais que charger des modeles 3D d'un fichier .obj + la texture, et les afficher. J'utilise une classe VBO pour masquer les details bas niveau.
Voici le code en question:
la classe Mesh qui contient les vbos et les affiche:
la classe ObjLoader qui char un fichier .obj et retourne les vbo des positions/textures/normals
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 class Mesh: def __init__(self, mesh_file, texture_file=None): loader = ObjLoader() self.vbos = loader.load(mesh_file) self.texture = None if texture_file: self.texture = texture.Texture(texture_file) def draw(self): if self.texture: self.texture.bind() for v in self.vbos: v.bind() glDrawArrays(GL_TRIANGLES, 0, len(self.vbos[0])) for v in self.vbos: v.unbind() if self.texture: self.texture.unbind()
la classe VBO
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 class ObjLoader: def load(self, obj_file): positions = [] normals = [] textures = [] faces = [] with open(obj_file) as f: for line in f: n = line.find('#') line = line[:n].strip().split() if line: if line[0] == 'v': positions += [map(float, line[1:4])] if line[0] == 'vn': normals += [map(float, line[1:4])] if line[0] == 'vt': textures += [map(float, line[1:3])] if line and line[0] == 'f': faces += \ map(self.parse_face, line[1:]) position_vbo = vbo.PositionVBO([positions[pos] for pos, _, _ in faces]) texture_vbo = vbo.TextureVBO([textures[tex] for _, tex, _ in faces]) normal_vbo = vbo.NormalVBO([normals[norm] for _, _, norm in faces]) return [position_vbo, texture_vbo, normal_vbo] def parse_face(self, vertex): pattern = '(?P<v>\d*)/(?P<vt>\d*)/(?P<vn>\d*)' r = re.match(pattern, vertex) v = r.group('v') vt = r.group('vt') vn = r.group('vn') if not v or not vt or not vn: raise ValueError, "obj file bad formatted" return map(lambda x: int(x) - 1, [v, vt, vn])
Le code qui exploite tout cela:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 class VBO: def __init__(self, data, usage=GL_STATIC_DRAW): self.buffer = GL.GLuint(0) self.buffer = glGenBuffers(1) self.count = len(data) self.size = len(data[0]) glBindBuffer(GL_ARRAY_BUFFER_ARB, self.buffer) data = numpy.array(data, dtype=numpy.float32) glBufferData(GL_ARRAY_BUFFER_ARB, ADT.arrayByteCount(data), ADT.voidDataPointer(data), usage) def __del__(self): print 'deleting vbo' glDeleteBuffers(1, GL.GLuint(self.buffer)) def __len__(self): return self.count def bind(self): glBindBuffer(GL_ARRAY_BUFFER_ARB, self.buffer) def unbind(self): glBindBuffer(GL_ARRAY_BUFFER_ARB, self.buffer) class PositionVBO(VBO): def bind(self): VBO.bind(self) glVertexPointerf(None) class TextureVBO(VBO): def bind(self): VBO.bind(self) glTexCoordPointerf(None) class NormalVBO(VBO): def bind(self): VBO.bind(self) glNormalPointerf(None) class ColorVBO(VBO): def bind(self): VBO.bind(self) glColorPointerf(None)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 # Initialisation d'OpenGL meshes = [] for i in range(20): meshes += [Mesh('data/objs/cube.obj', 'data/textures/texture.jpg')] while True: # Preparation du rendu for i, m in enumerate(meshes): # transformer et une classe qui se charge des transformation 3d(translation + rotation) transformer.translate(Vector(i, 0, 0)) m.draw() # Fin du rendu, on efface l'ecran
Partager