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:
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 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
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])
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
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)
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
 
 
# 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