1. #1
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2013
    Messages
    121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : août 2013
    Messages : 121
    Points : 55
    Points
    55

    Par défaut Rendu de terrain très lent - shaders or not shaders ?

    Bonjour à tous, je code en ce moment un petit simulateur avec une map contenant un nombre relativement élevé de vertices (Plusieurs dizaines de milliers), et force est de constater que mon PC atteint vite ses limites en terme de performances, la map est en fait constituée de plusieurs massifs et lorsqu'ils sont tous dessinés, ça lague comme pas possible, tous est saccadé ! Mon PC est un HP Pavilion G6 tournant sous Windows 8, j'ai testé sur un autre PC (Un Asus F541U sous Windows 10) et la différence est flagrante : C'est bien plus fluide, mais on sent quand même la différence selon si un seul massif est dessiné ou bien tous.

    Mon programme utilise SDL et OpenGL et est écrit en C, on y trouve une structure "Principale" contenant tous les paramètres du simulateur (Paramètres écran, caméra) notamment une structure de type "Terrain". Le tout est lu dans un fichier .obj créé avec Blender. Pour résumer :

    Fichier d'en-tête :

    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
    typedef struct Vertex			//Sommet des polygones
    {
        float x;
        float y;
        float z;
        float xTex;
        float yTex;
    }Vertex;
     
    typedef struct Face			//Polygones constituée de vertices
    {
        Vertex *vertices;
        int nbVertices;
        GLint texture;
        float couleur[3];
    }Face;
     
    typedef struct Objet		//Objet constituée de polygones
    {
        Face *faces;
        int nbFaces;
        bool textures;
    }Objet;
     
    typedef struct Massif			//Massif constitué d'objets
    {
        Objet Meshes[MAX_OBJETS];
        int nbObjets;
        float X;
        float Y;
    }Massif;
     
    typedef struct Terrain			//Terrain constitué de massifs
    {
        Massif liste_massifs[NB_MASSIFS];
    }Terrain;
     
    typedef struct Principale
    {
        /*...*/
     
        Terrain Map;
    }Principale;
    Le main :

    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
    44
    45
    46
    int main(int argc,char *argv[])
    {
        SDL_Surface *fenetre;
        SDL_Event evenement;
     
        Principale infos;		//Tous les paramètres du simulateur
     
        if(SDL_Init(SDL_INIT_VIDEO)<0)
            return -1;
     
        Init(&infos);
     
        fenetre=SDL_SetVideoMode(800,600,32,SDL_OPENGL);
     
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
     
        gluPerspective(FOVY_INIT,4.0/3,NEAR,FAR);
     
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_DEPTH_TEST);
     
        chargeTextures(&infos);
        chargement(&infos);
     
        while(1)
        {
            SDL_PollEvent(&evenement);
            if(evenement.type==SDL_QUIT)
                break;
            if(evenement.type==SDL_KEYDOWN)
            {
                if(evenement.key.keysym.sym==SDLK_ESCAPE)
                    break;
            }
     
            gestionCam(&infos,&evenement);
            Dessiner(&infos);
     
            SDL_GL_SwapBuffers();
            glFlush();
        }
     
        SDL_Quit();
        return 0;
    }
    Fonction chargement() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    {
    	chargeMassif(&ptr->Map.liste_massifs[0],"Massif1");
    	chargeMassif(&ptr->Map.liste_massifs[1],"Massif2");
    	chargeMassif(&ptr->Map.liste_massifs[2],"Massif3");
    }
    La fonction chargeMassif() parcourt ensuite le fichier .obj et liste tous les vertices et toutes les coordonnées de textures pour tout stocker en mémoire.

    Fonction Dessiner() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    {
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
     
        gluLookAt(ptr->xCam,ptr->yCam,ptr->zCam,ptr->xCible,ptr->yCible,ptr->zCible,0,0,1);
     
        glClearColor(0,0.5,1,1);
     
        dessinMap(ptr);
    }
    Fonction dessinMap() :

    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
    {
        int compteurMassifs=0;
        const float tailleMap=100000;
        const int multiplTex=10000;
     
        dessinTerrain(&ptr->Map);
     
        while(1)
        {
            glPushMatrix();
            glTranslated(ptr->Map.liste_massifs[compteurMassifs].X,ptr->Map.liste_massifs[compteurMassifs].Y,0);
            glScalef(1000,1000,1000);		//Echelle en mètres
            dessinMassif(&ptr->Map.liste_massifs[compteurMassifs]);
            glPopMatrix();
     
            compteurMassifs++;
            if(compteurMassifs==NB_MASSIFS)
                break;
        }
    }
    Fonction dessinMassif() :

    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
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    {
        int compteurMeshes=0,compteurFaces,compteurVertices;
     
        while(1)			//Dessin des objets
        {
            compteurFaces=0;
            while(1)
            {
                if(massif->Meshes[compteurMeshes].faces[compteurFaces].texture!=-1)		//Si la face est texturée
                {
                    glEnable(GL_TEXTURE_2D);
                    glBindTexture(GL_TEXTURE_2D,(GLuint)massif->Meshes[compteurMeshes].faces[compteurFaces].texture);
                }
     
                if(massif->Meshes[compteurMeshes].faces[compteurFaces].texture==-1)		//Si la face n'est pas texturée
                    glDisable(GL_TEXTURE_2D);
     
                glColor3d(massif->Meshes[compteurMeshes].faces[compteurFaces].couleur[0],		//Coloration
                          massif->Meshes[compteurMeshes].faces[compteurFaces].couleur[1],
                          massif->Meshes[compteurMeshes].faces[compteurFaces].couleur[2]);
     
                //Dessin des polygones
    	    if(compteurFaces==0)
                {
                    if(massif->Meshes[compteurMeshes].faces[compteurFaces].nbVertices==3)
                        glBegin(GL_TRIANGLES);
                    if(massif->Meshes[compteurMeshes].faces[compteurFaces].nbVertices==4)
                        glBegin(GL_QUADS);
                    if(massif->Meshes[compteurMeshes].faces[compteurFaces].nbVertices>=5)
                        glBegin(GL_POLYGON);
                }
                if(compteurFaces!=0)
                {
                    if(massif->Meshes[compteurMeshes].faces[compteurFaces].nbVertices!=massif->Meshes[compteurMeshes].faces[compteurFaces-1].nbVertices||
                       massif->Meshes[compteurMeshes].faces[compteurFaces].texture!=massif->Meshes[compteurMeshes].faces[compteurFaces-1].texture)
                    {
                        if(massif->Meshes[compteurMeshes].faces[compteurFaces].nbVertices==3)
                            glBegin(GL_TRIANGLES);
                        if(massif->Meshes[compteurMeshes].faces[compteurFaces].nbVertices==4)
                            glBegin(GL_QUADS);
                        if(massif->Meshes[compteurMeshes].faces[compteurFaces].nbVertices>=5)
                            glBegin(GL_POLYGON);
                    }
                }
     
                compteurVertices=0;			//Dessin des vertices
                while(1)
                {
                    glTexCoord2f(massif->Meshes[compteurMeshes].faces[compteurFaces].vertices[compteurVertices].xTex,
                                 massif->Meshes[compteurMeshes].faces[compteurFaces].vertices[compteurVertices].yTex);
     
                    glVertex3f(massif->Meshes[compteurMeshes].faces[compteurFaces].vertices[compteurVertices].x,
                               massif->Meshes[compteurMeshes].faces[compteurFaces].vertices[compteurVertices].y,
                               massif->Meshes[compteurMeshes].faces[compteurFaces].vertices[compteurVertices].z);
     
                    compteurVertices++;
                    if(compteurVertices==massif->Meshes[compteurMeshes].faces[compteurFaces].nbVertices)
                        break;
                }
                if(compteurFaces!=massif->Meshes[compteurMeshes].nbFaces-1)
                {
                    if(massif->Meshes[compteurMeshes].faces[compteurFaces].nbVertices!=massif->Meshes[compteurMeshes].faces[compteurFaces+1].nbVertices||
                       massif->Meshes[compteurMeshes].faces[compteurFaces].texture!=massif->Meshes[compteurMeshes].faces[compteurFaces+1].texture)
                        glEnd();
                }
                if(compteurFaces==massif->Meshes[compteurMeshes].nbFaces-1)
                    glEnd();
     
                compteurFaces++;
                if(compteurFaces==massif->Meshes[compteurMeshes].nbFaces)
                    break;
            }
     
            compteurMeshes++;
            if(compteurMeshes==massif->nbObjets)
                break;
        }
     
        glEnable(GL_TEXTURE_2D);
        glColor3d(1,1,1);
    }
    Alors effectivement ça fait beaucoup de while dans un while ... Je me doute que ça contribue à ralentir l'exécution mais je ne vois pas d'autre solution à moins peut-être d'utiliser les shaders, mais avant de me lancer là-dedans, j'aimerais avoir des avis pour savoir si les shaders sont une solution pour ce problème.
    Petite parenthèse aussi : Je remarque qu'à chaque fois que mes programmes tournent sous Windows 10, la visibilité est réduite et la précision de l'affichage réduite (On voit les surfaces à travers les autres).

    Merci d'avance.

  2. #2
    Membre expert
    Homme Profil pro
    Développeur .NET
    Inscrit en
    novembre 2009
    Messages
    1 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : novembre 2009
    Messages : 1 469
    Points : 3 457
    Points
    3 457

    Par défaut

    J'ai aucune idée sur le fond du problème et je pense pas que ma solution va changer grand chose à ton problème, mais je remarque que dans ta procédure dessinMassif tu n'utilises pas de if/else
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
                if(massif->Meshes[compteurMeshes].faces[compteurFaces].texture!=-1)		//Si la face est texturée
               ......
     
                if(massif->Meshes[compteurMeshes].faces[compteurFaces].texture==-1)		//Si la face n'est pas texturée
     
     ...........
    	    if(compteurFaces==0)
               ......
                if(compteurFaces!=0)
    Tu fais 2 tests pour rien, multiplié par le nombre ca a forcément une incidence. Bon après peut etre que le compilateur détecte ce genre de chose.

  3. #3
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    octobre 2008
    Messages
    148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : octobre 2008
    Messages : 148
    Points : 258
    Points
    258

    Par défaut

    Quelques dizaines de milliers de vertices c'est rien du tout pour une carte graphique, même ancienne. Ton problème vient du fait que tu n'utilise pas du tout les bonnes structures de données ni les fonctions modernes d'OpenGL. glPushMatrix, glPopMatrix, glScalef, glColor3d, tout ça est obsolète aujourd'hui... En plus tu utilse une texture par face ce qui est très inefficace.

    La bonne manière de faire c'est de créer un buffer de vertex que tu envoie directement à ta carte graphique une bonne fois pour toute, que tu lie à un shader et à une texture, puis que tu affiche à l'écran avec une seule commande. Pas besoin de parcourir ta structure de données à chaque fois !

    En général, on représente les mesh de cette manière:

    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
    44
     
    struct Mesh
    {
    	// buffer est un tableau qui contient tous les vertices de ton objet
    	// il est organisé comme ça:
    	// vertex0_x, vertex0_y, vertex0_z, vertex1_x, vertex1_y, ...
    	float* vertex_buffer;
     
    	// contient les liste des coordonnées des texture
    	// il est organisé comme ça:
    	// vertex0_xTex, vertex0_yTex, vertex1_xTex, ...
    	float* vertex_buffer_uv;
     
    	// combien de vertice ce buffer contient
    	// la taille de  vertex_buffer est donc de nb_vertices * 3 * sizeof(float)
    	// et la taille de  vertex_buffer_uv est donc de nb_vertices * 2 * sizeof(float)
    	int nb_vertices;
     
    	// les sous mesh correspondent à des draw calls, c'est-à-dire des commandes de rendu
    	// chaque sous-mesh est lié à une texture et à un shader
    	SubMesh* sub_meshes;
     
    	// combien de sous mesh a-t-on dans sub_meshes
    	int nb_sub_meshes;
     
    	// l'identifiant openGL du vertex buffer et du vertex buffer uv
    	GLInt vertex_buffer_id;
    	GLInt vertex_buffer_uv_id;
    };
     
    struct SubMesh
    {
    	// quel est l'indice de départ dans le tableau vertex_buffer
    	int vertex_start_index;
     
    	// combien ce sous mesh contient de vertex
    	int vertex_count;
     
    	// identifiant de texture
    	GLInt texture_id;
     
    	// identifiant de shader
    	GLInt shader_id;
    };
    Au début du programme, tu charge les données et tu envoie le buffer à la carte graphique. En pseudo code:

    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
     
    Mesh* ChargerJeu()
    {
    	float* vertex_buffer;
    	float*  vertex_buffer_uv;
    	int nb_vertices;
    	SubMesh* sub_meshes;
    	int nb_sub_meshes;
    	LireFichier("myMesh", &vertex_buffer, &vertex_buffer_uv, &nb_vertices, &sub_meshes, &nb_sub_meshes);
     
    	Mesh* mesh = malloc(sizeof(Mesh));
    	mesh->vertex_buffer = vertex_buffer;
    	mesh->vertex_buffer_uv = vertex_buffer_uv;
    	mesh->nb_vertices = nb_vertices;
    	mesh->sub_meshes = sub_meshes;
    	mesh->nb_sub_meshes = nb_sub_meshes;
     
    	mesh->vertex_buffer_id = glCreateVertexBuffer();
    	glSendVertexBufferData(mesh->vertex_buffer_id, mesh->vertex_buffer, mesh->nb_vertices, GL_BUFFER_FLOAT3);	
     
     
    	mesh->vertex_buffer_uv_id = glCreateVertexBuffer();
    	glSendVertexBufferData(mesh->vertex_buffer_uv_id, mesh->vertex_buffer_uv, mesh->nb_vertices, GL_BUFFER_FLOAT2);	
     
    	return mesh;
    }
    et enfin, dans la boucle de rendu, tu affiche chacun des sous-mesh à la suite:

    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
     
    void AfficherMesh(Mesh* ùesh)
    {
    	// on indique à openGL d'utiliser ce vertex buffer et ce vertex buffer id
    	glSetActiveVertexBuffer(vertex_buffer_id);
    	glSetActiveVertexUVBuffer(vertex_buffer_uv_id);
     
    	for (int i = 0; i < mesh->nb_sub_meshes; ++i)
    	{
    		// on indique à openGL d'utiliser cette texture
    		glSetActiveTexture(mesh->sub_meshes[i]->texture_id);
     
    		// on indique à openGL d'utiliser ce shader
    		glSetActiveShader(mesh->sub_meshes[i]->shader_id);
     
    		// on spécifie la position de la caméra dans le shader
    		glSetShaderParam(mesh->sub_meshes[i]->shader_id, "camera_matrix", camMatrix);    
     
    		// on affiche les vertices du mesh
    		glDrawPrimitive(GL_PRIMITIVE_TRIANGLE, mesh->sub_meshes[i]->vertex_start_index, mesh->sub_meshes[i]->vertex_count);
    	}
    }
    Je précise bien qu'il s'agit de pseudo code, je ne me souvient pas de mémoire quels sont les vraies fonctions openGL à appeler. Je te conseille de lire des tutoriels sur OpenGL moderne !

  4. #4
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2013
    Messages
    121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : août 2013
    Messages : 121
    Points : 55
    Points
    55

    Par défaut

    micka132, bonne remarque, je vais tester et voir ce que ça donne, c'est effectivement inutile de faire plusieurs fois le même test.

    dancingmad, c'est vrai que j'utilise une version ancienne d'OpenGL. Si je comprends bien, tu me suggères d'utiliser des tableaux de float pour les vertices et pour les coordonnées de texture au lieu de déclarer des structures, corrige moi si je me trompe mais ce que tu appelles des sous meshes peut s'apparenter à des polygones ?

    Tu utilse une texture par face ce qui est très inefficace
    C'est parce que chaque face doit avoir sa propre texture et sa propre couleur.

    Quelques dizaines de milliers de vertices c'est rien du tout pour une carte graphique, même ancienne
    Ça se voit que tu connais pas mon PC, un escargot serait plus rapide xD

    Merci pour vos réponses en tout cas.

  5. #5
    Membre actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    octobre 2008
    Messages
    148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : octobre 2008
    Messages : 148
    Points : 258
    Points
    258

    Par défaut

    Citation Envoyé par KevinduC Voir le message
    Si je comprends bien, tu me suggères d'utiliser des tableaux de float pour les vertices et pour les coordonnées de texture au lieu de déclarer des structures
    Oui tout à fait. Comme ça, les tableaux sont directement stockés dans la mémoire de la carte graphique et les traitements sont faits en interne. C'est bien plus rapide !

    Citation Envoyé par KevinduC Voir le message
    ce que tu appelles des sous meshes peut s'apparenter à des polygones ?
    Oui un peu. Mesh = maillage en anglais, c'est-à-dire des points reliés entre eux. Tu peux voir ça comme une liste de triangles qui doivent être rendus de la même façon (même texture et même shader en gros).

    Imagine un personnage en 3D : il est constistué d'un grand nombre de vertices (environ 1 million pour un perso d'un gros jeu AAA), mais chaque partie doit être rendu d'une manière différente. On va par exemple avoir:
    - une texture pour la tête et les mains avec un shader spécial
    - une texture pour les vêtements
    - une texture pour l'arme
    - etc.

    Comme on ne peut utiliser qu'un seul shader et qu'un petit nombre de texture à la fois, on est obligé de découper ce mesh en sous parties (ou submesh) et rendre chaque partie séparément. Chaque commande de rendu est appelé "draw call" et en gros, moins tu en as, plus rapide ça sera.

    Citation Envoyé par KevinduC Voir le message
    C'est parce que chaque face doit avoir sa propre texture et sa propre couleur.
    Alors pour la couleur, c'est vrai que je ne l'ai pas précisé, mais pour ça tu doit avoir encore un autre tableau de float qui contient les informations de couleurs de chaque pixel. Au moment du rendu, comme pour les tableau de position et celui de coordonnées et texture tu dois indiquer à OpenGL que tu va utiliser ce tableau pour faire des couleurs.

    Sinon tu a vraiment une texture par face ? Ça m'étonne un peu

    Ce que je te suggère c'est de faire comme dans l'exemple du personnage et de mettre ensemble les faces qui utilisent la même texture dans un seul sous-mesh. Sinon tu seras obligé de faire un draw call par face, et là tu perds tout l'intérêt des vertex buffer...

    Edit: j'avais pas vu ta remarque suivante:

    Citation Envoyé par KevinduC Voir le message
    Ça se voit que tu connais pas mon PC, un escargot serait plus rapide xD
    10000 vertex c'est beaucoup moins que ce que pouvait afficher les premiers PC au début de la 3D, alors à moins que le tiens ne date des années 90, crois-moi 10k vertex c'est vraiment rien du tout. Aujourd'hui les PC milieu de gamme peuvent afficher sans problèmes de scènes avec des dizaines de millions de polygones.

  6. #6
    Expert éminent
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    mai 2010
    Messages
    2 148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : mai 2010
    Messages : 2 148
    Points : 6 172
    Points
    6 172

    Par défaut

    Citation Envoyé par KevinduC Voir le message
    Ça se voit que tu connais pas mon PC, un escargot serait plus rapide xD
    Le souci vient plus de ton code (même avec OpenGL 1 on peut esperer faire mieux), j'avais tester sur mon vieux eeePC (pas de CG juste un chipset) , il fait les 10000 vertex les doigt dans le nez ( a 60 fps pourtant).

    On va dire que glBegin /glVertex3f c'est le truc le plus long au monde , si tu bosse sur un vieux pc et que tu peux pas faire de OpenGL moderne , utilise deja les VA , y'a une sacrée différence (ensuite ton code est mal foutu aussi , ça n'aide pas).

  7. #7
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2013
    Messages
    121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : août 2013
    Messages : 121
    Points : 55
    Points
    55

    Par défaut

    Ok je vois le truc, il s'agit de regrouper les vertices, les sous meshes permettent de piocher une portion correspondant aux polygones.

    Citation Envoyé par dancingmad Voir le message
    Sinon tu a vraiment une texture par face ? Ça m'étonne un peu
    Dans les massifs que je dessine certaines faces représentent de l'herbe, d'autres du calcaire ..., je ne peux donc pas appliquer une texture unique pour un mesh.

    Citation Envoyé par Kannagi Voir le message
    On va dire que glBegin /glVertex3f c'est le truc le plus long au monde
    C'est pour ça que j'ai codé ma fonction de sorte à ce qu'elle n'appelle glBegin() et glEnd() uniquement lorsqu'il y a changement de texture ou de nombre de vertices.

    Tu veux parler des Vertex Array ? J'en avais déjà entendu parler, je vais me pencher sur le sujet.

  8. #8
    Expert éminent sénior

    Profil pro
    Développeur informatique
    Inscrit en
    novembre 2006
    Messages
    6 422
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : novembre 2006
    Messages : 6 422
    Points : 12 858
    Points
    12 858

    Par défaut

    Citation Envoyé par KevinduC Voir le message
    mais ce que tu appelles des sous meshes peut s'apparenter à des polygones ?
    oui c'est exact ; plusieurs polygones définissent un objet en fait une mesh en anglais ce n'est ni plus ni moins qu'un maillage
    Pour faire un polygone et notamment un quadrilatère il faut lier deux triangles par leur côté opposé

    Citation Envoyé par KevinduC Voir le message
    Alors effectivement ça fait beaucoup de while dans un while ... Je me doute que ça contribue à ralentir l'exécution mais je ne vois pas d'autre solution à moins peut-être d'utiliser les shaders, mais avant de me lancer là-dedans, j'aimerais avoir des avis pour savoir si les shaders sont une solution pour ce problème.
    je doute que les shaders permettront d'accéler le rendu.
    C'est certain que c'est mieux mais rien ne garantit un rendu plus fluide.La différence avec les shaders c'est que le code dans le cas des shaders c'est du rendu GPU au lieu du code C/C++ qui est du code CPU avec des envois de dessin au GPU.
    Le problème c'est effectivement les boucles imbriquées avec des while dans des while.
    Et avec du langage pour shaders il faudra faire des boucles comme même.
    Donc il faut avoir recours à des techniques d'optimisation comme les view frustrum, arbres de tri des faces..

    consulter les tutos de ce forum ( bref DVP ) il me semble en avoir vu
    Ne dites pas : "chercher la petite bête" mais plutôt "effectuer un travail d'entomologiste."
    Pour corriger des bugs c'est pareil

  9. #9
    Expert éminent

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    juin 2005
    Messages
    1 780
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juin 2005
    Messages : 1 780
    Points : 9 305
    Points
    9 305
    Billets dans le blog
    4

    Par défaut

    Il faut savoir que là tu utilises le code de la première spécification d'OpenGL (glBegin, glEnd), ensuite, il y a eu les display lists (on gardait les glBegin/glEnd, mais on stockait ces appels dans une liste de commandes, que l'on exécutait ensuite, ce qui permettait déjà un gain, car on ne parcourait plus ses données à chaque frame).
    Mais ça, c'était très lent. Ensuite sont venus les vertex arrays, où on donnait les donnée des sommets (positions, normales, coordonnées de texture, couleurs) dans des buffers, directement à la fonction de dessin. C'était déjà beaucoup mieux, mais pas encore idéal, car on faisait le transfert à chaque draw call.
    Puis sont arrivés les Vertex Buffer Objects (VBO), qui permettent d'effectuer ce transfert en amont, puis de n'utiliser que l'identifiant du buffer lors du draw call, ce qui accélère encore le rendu.
    Donc comme tu peux le voir, tu utilises quelque chose pour le moins antique, dont il faut te débarasser au plus vite.

    Ensuite, tu peux très bien garder tes structures, et les stocker telles quelles dans un buffer, c'est ce qu'on appelle des données entrelacées (interleaved buffer), et les attributs de sommets permettent de définir les propriétés de cet entrelacement.

    Concernant les shaders, sache qu'en interne le driver de ta carte graphique s'en sert déjà, et comme tu n'y connais pour l'instant rien, je doute que tu écrives du GLSL plus optimisé que le driver.
    Donc, pour commencer, je te conseille de te pencher sur les VBO, en utilisant des fonctions dépréciées, mais qui te permettront, pour commencer, de tester la validité de tes données : glVertexPointer, glColorPointer, ...

    Enfin, je ne peux que te conseiller de consulter les tutoriels OpenGL moderne présents dans la section tutoriels de ce forum (tu en trouveras un dans ma signature).
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  10. #10
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2013
    Messages
    121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : août 2013
    Messages : 121
    Points : 55
    Points
    55

    Par défaut

    Merci pour vos réponses, je suis entrain de suivre des tutos sur les Vertex Array, j'ai consacré la soirée à refaire depuis le début la lecture du fichier .obj conformément à ce qui est indiqué dans le tuto et je n'ai pas terminé, mais je m'arrête là sinon je me couche pas avant 5h du matin ^^

    Bref merci pour vos conseils.

  11. #11
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2013
    Messages
    121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : août 2013
    Messages : 121
    Points : 55
    Points
    55

    Par défaut

    Bon bah je suis bloqué finalement, jusqu'à présent j'ai procédé comme suit :

    - Je parcours la liste des vertices dans le fichier .obj et je stocke le tout dans un tableau de float de la forme : [X0, Y0, Z0, X1, Y1, Z1, ...]

    - Je parcours la liste des coordonnées de texture dans le même fichier et je stocke le tout dans un autre tableau de float de la forme : [X0, Y0, X1, Y1, ...]

    - J'appelle une fonction qui modifie l'ordre du tableau des coordonnées de texture, si par exemple dans notre fichier .obj nous avons "f 1/2 2/3 3/5", cela signifie que nous avons un triangle constitué des vertices 1, 2 et 3 (Donc 0, 1 et 2 dans le tableau de vertices) et qu'à chacun de ces sommets correspondent les coordonnées de texture 2, 3 et 5 (Donc 1, 2 et 4 dans le tableau de coordonnées de texture)

    Il faut donc mettre la coordonnée de texture 2 à la première position dans le tableau de coordonnées de texture donc au rang 0. Quant à la coordonnée de texture 3, c'est plus compliqué car les données sont regroupées par paires, il faut donc faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    nvellePosition = 2*numVertex - 2;
    anciennePosition = 2*numCoordTex - 2;
     
    nveauTableau[nvellePosition] = ancienTableau[anciennePosition];
    nveauTableau[nvellePosition+1] = ancienTableau[anciennePosition+1];
    Et bien vous savez quoi ? Tout ceci est faux, car les fichiers .obj stockent les vertices par face, on peut donc très bien avoir :

    "f 1/2 2/3 3/5"
    "f 1/5 4/8 6/12"

    Dans ce cas, la fonction va mettre les coordonnées de texture 2 au niveau du vertex 1 puis elle va effectuer la même opération lorsqu'elle va retomber sur le vertex 1, elle va donc mettre au niveau de ce vertex les coordonnées de texture 5, ce qui va écraser les anciennes valeurs.

    Auriez-vous une solution pour contourner cela ?

  12. #12
    Expert éminent

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    juin 2005
    Messages
    1 780
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juin 2005
    Messages : 1 780
    Points : 9 305
    Points
    9 305
    Billets dans le blog
    4

    Par défaut

    PLlutôt que de modifier tes buffers, il faut en construire un nouveau, le résultat, qui contiendra les sommets (position + texcoords) des différentes faces.
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  13. #13
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2013
    Messages
    121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : août 2013
    Messages : 121
    Points : 55
    Points
    55

    Par défaut

    Merci bien, j'ai changé de stratégie : La fonction chargeMassif() liste l'ensemble des coordonnées de vertices du fichier .obj qu'elle stocke dans un tableau provisoire puis elle fait la même chose avec les coordonnées de texture, puis elle revient au début du fichier et appelle une fonction chargeVA(). Cette dernière récupère les lignes commençant par "usemtl" (Pour alors aller récupérer la texture et la couleur dans le fichier .mtl) ainsi que celles commençant par "f", où elle appelle alors une fonction chargeVerticesFace() qui décortique la ligne afin de pouvoir aller piocher les données dans les tableaux provisoires.
    Il y a dans la structure principale un tableau de structures de type Massif, chacune constituée de :

    - Un tableau de float pour les coordonnées des vertices
    - Un autre pour les coordonnées de texture
    - Un autre pour les couleurs
    - Un tableau de int pour le nombre de vertices pour chaque face
    - Un entier indiquant le nombre total de vertices.

    Voici une partie du code chargeMassif() :

    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
    44
    45
    if(fichierObj!=NULL&&fichierMtl!=NULL)
    {
        while(1)                //Stockage de tous les vertices dans un tableau provisoire
        {
            retour_fgets=fgets(ligneLue,taille_max_ligne,fichierObj);
            if(retour_fgets==NULL)
                break;
     
            if(ligneLue[0]=='v'&&ligneLue[1]==' ')
            {
                sscanf(ligneLue,"v %f %f %f\n",
                       &liste_vertices[compteurVertices].x,
                       &liste_vertices[compteurVertices].y,
                       &liste_vertices[compteurVertices].z);
     
                compteurVertices++;
            }
     
            if(ligneLue[0]=='v'&&ligneLue[1]=='t')
            {
                sscanf(ligneLue,"vt %f %f\n",
                       &coord_textures[compteurCoordTex].x,
                       &coord_textures[compteurCoordTex].y);
     
                compteurCoordTex++;
            }
        }
     
        rewind(fichierObj);
     
        massif->vertices=(float*)malloc(MAX_TOTAL_VERTICES*3*sizeof(float));
        massif->coord_tex=(float*)malloc(MAX_TOTAL_VERTICES*2*sizeof(float));
        massif->couleurs=(float*)malloc(MAX_TOTAL_VERTICES*3*sizeof(float));
        massif->nbVerticesParFace=(int*)malloc(MAX_TOTAL_FACES*sizeof(int));
     
        chargeVA(fichierObj,fichierMtl,massif,liste_vertices,coord_textures);
     
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glEnableClientState(GL_COLOR_ARRAY);
     
        glVertexPointer(3,GL_FLOAT,3*sizeof(float),massif->vertices);			//X Y Z
        glTexCoordPointer(2,GL_FLOAT,2*sizeof(float),massif->coord_tex);		//X Y
        glColorPointer(3,GL_FLOAT,3*sizeof(float),massif->couleurs);		//R V B
    }
    La fonction dessinMassif() est appelée en boucle, voici son contenu :

    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
    int compteurFaces=0,nbVertices,first=0;
        nbVertices=massif->nbVerticesParFace[compteurFaces];
     
    while(1)    
    {	
        if(nbVertices==3)
        {
            glDrawArrays(GL_TRIANGLES,first,3);
            first+=3;
        }
     
        if(nbVertices==4)
        {
            glDrawArrays(GL_QUADS,first,4);
            first+=4;
        }
     
        if(nbVertices>=5)
        {
            glDrawArrays(GL_POLYGON,first,nbVertices);
            first+=nbVertices;
        }
     
        compteurFaces++;
     
        if(first>=massif->nbTotalVertices)
            break;
    }
    Seulement voilà, lorsque je charge deux massifs, je me rends compte que le premier est mal dessiné, les données ont été apparemment écrasées par le deuxième chargement. Je ne parviens pas à trouver l'origine du problème.

    Edit : Je me pose également la question des textures : Comment attribuer une texture aux différents vertices ?? On peut spécifier des coordonnées dans l'espace, des coordonnées de texture et une couleur mais je ne trouve rien pour l'équivalent avec les textures.

  14. #14
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2013
    Messages
    121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : août 2013
    Messages : 121
    Points : 55
    Points
    55

    Par défaut

    J'ai fait un essai en utilisant un tableau de GLint chargé au début du programme mais le problème c'est que je ne sais pas comment l'envoyer à la CG. En utilisant ce tableau présent dans la RAM, ça fait de nouveau ramer le programme.

  15. #15
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2013
    Messages
    121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : août 2013
    Messages : 121
    Points : 55
    Points
    55

    Par défaut

    J'ai voulu passer aux VBO plutôt que les VA mais Code::Blocks ne reconnaît pas les fonctions glewInit() et glGenBuffers(), le compilateur affiche :

    "undefined reference to '_imp__glewInit@0'
    "undefined reference to '_imp____glewGenBuffers'

    Pourtant, glew.h est bien inclus, et j'ai ajouté glew32.lib, glew32s.lib et libglew32s.

    Bref je suis bloqué à cause d'une erreur de compilation. J'ai fouillé sur Internet sans résultat. Si qq1 a une solution ...

  16. #16
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    22 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 22 695
    Points : 158 431
    Points
    158 431
    Billets dans le blog
    12

    Par défaut

    Bonjour,

    L'erreur provient de l'éditeur de liens. Voici la solution. Et n'hésitez pas à lire tout l'article pour bien comprendre et ne plus jamais avoir de problème.

    Pour la mise en place, avez-vous vu ce tutoriel. Je pense que vous écrasez vos données en chargeant un deuxième massif.
    Du coup, il faudrait plutôt faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Pour autant de massif que nécessaire
        Génération du massif
        Envoie à la CG
    Et à l'affichage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Pour autant de massif que nécessaire
        Affichage massif N
    Combien de RAM prenez vous par massif ? Combien il y a de sommets par massif. Cela me semble super gros.
    Je conseille de passer par les VBO, qui permettront de stocker les données des massifs dans la mémoire vidéo (et ainsi, ne pas avoir plus d'un massif en RAM). Mais attention, la mémoire vidéo a aussi une limite.
    Faites vous de la réutilisation de sommets ? Ou dupliquez vous les sommets lorsqu'ils sont utilisées par plusieurs triangles du modèle ?
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  17. #17
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2013
    Messages
    121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : août 2013
    Messages : 121
    Points : 55
    Points
    55

    Par défaut

    Merci pour votre réponse, le problème vient effectivement de l'éditeur de liens, mais je ne trouve pas la ou les bibliothèque(s) à installer. J'ai fouillé sur Google mais les quelques fichiers .a ou .lib que j'ai trouvés n'ont pas permis de résoudre le problème. Moi qui comptais sur les VBO je suis bloqué à cause de ça !

    Pour le problème des données écrasées, j'ai changé de méthode : Je charge toute la map en une seule fois et je fais donc un seul appel à gl*Pointer() parce qu'apparemment, on ne peut utiliser ces fonctions qu'une seule fois.

  18. #18
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    22 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 22 695
    Points : 158 431
    Points
    158 431
    Billets dans le blog
    12

    Par défaut

    Pour GLEW, prenez vous la version 32 bits ou 64 bits ? Sachant que vous avez CodeBlocks, c'est la version 32 bits qu'il faut prendre (car ça dépend de l'architecture du compilateur et non de la machine).
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  19. #19
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2013
    Messages
    121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : août 2013
    Messages : 121
    Points : 55
    Points
    55

    Par défaut

    Je pense que c'est la 32 bits puisque le seul fichier .a de GLEW dont je dispose s'appelle "libglew32s.a"

  20. #20
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    mai 2008
    Messages
    22 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : mai 2008
    Messages : 22 695
    Points : 158 431
    Points
    158 431
    Billets dans le blog
    12

    Par défaut

    Pour utiliser ce fichier (le .a) (car les .lib sont généralement pour MSVC), il faut utiliser la macro GLEW_STATIC. Normalement, la documentation officielle l'indique. Sinon, il faudrait que je prenne du temps pour essayer chez moi.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [OpenGL 3.x] Problème envoi de données du geometry shader au fragment shader
    Par kirkm9 dans le forum OpenGL
    Réponses: 4
    Dernier message: 01/05/2016, 05h57
  2. pixel shader 2.0
    Par trois_1 dans le forum DirectX
    Réponses: 3
    Dernier message: 20/10/2003, 16h39
  3. Vertex et Pixel Shader
    Par Riko dans le forum OpenGL
    Réponses: 2
    Dernier message: 06/06/2003, 17h45
  4. carte graphique et pixels shader
    Par yeeep dans le forum DirectX
    Réponses: 2
    Dernier message: 26/04/2003, 11h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo