IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

3D Java Discussion :

[JOGL] Utilisation de shaders personnalisés


Sujet :

3D Java

  1. #1
    Membre actif Avatar de Chen norris
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2004
    Messages : 216
    Points : 248
    Points
    248
    Par défaut [JOGL] Utilisation de shaders personnalisés
    Bonjour à tous,

    Après plusieurs recherches et pas mal de lecture à travers les tutos qu'on peut trouver sur le net, je me résouds à venir demander ici de l'aide.

    Je cherche à reprendre un modeleur 3D que j'avais développé il y a quelques temps en C# avec la librairie XNA pour le basculer en Java avec la librairie OpenGL (pour des raisons de compatibilités et surtout de maintenance, Microsoft ayant la désagréable habitude de repenser complètement ses architectures). J'utilise aussi le binding JOGL. J'ai pour le moment pas mal avancé puisque j'arrive à charger mes scènes depuis des fichiers XML, et à les afficher avec couleurs et textures. Le point sur lequel je bloque maintenant est la mise en place des shaders. J'arrive à comprendre la logique très globale qui est Scène 3D → Vertex Shader → Fragment Shader → Rendu à l'écran (je simplifie ici volontairement le pipeline graphique) mais en ce qui concerne les différents appels de structure à lancer, j'avoue que je me perds un peu les pédales.

    Pour rentrer dans le vif du sujet, j'ai suivi la logique de rendu suivante : (c'est très très simplifié par rapport à mon projet où tout est découpé dans différentes classes)
    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
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
     
    public class Renderer implents GLEventListener {
        ...
        public int shaderProgram;
        public int vertexShader;
        public int fragmentShader;
        ...
        @Override
        public void init(GLAutoDrawable drawable) {
            GL2 gl = drawable.getGL().getGL2();
            shaderProgram = gl.glCreateProgram();
            vertexShader = gl.glCreateShader(GL2.GL_VERTEX_SHADER);
            fragmentShader = gl.glCreateShader(GL2.GL_FRAGMENT_SHADER);
     
            // Compilation du vertex shader
            String content = new String(Files.readAllBytes(Paths.get("vertexShader.glsl")), Charset.defaultCharset());
            String[] shaderContent = new String[] { content };
            gl.glShaderSource(vertexShader, 1, shaderContent, new int[] { shaderContent[0].length() }, 0);
            gl.glCompileShader(vertexShader);
            gl.glGetShaderiv(vertexShader, GL2.GL_COMPILE_STATUS, compiled, 0);
     
            // Compilation du fragment shader
            content = new String(Files.readAllBytes(Paths.get("fragmentShader.glsl")), Charset.defaultCharset());
            shaderContent = new String[] { content };
            gl.glShaderSource(fragmentShader, 1, shaderContent, new int[] { shaderContent[0].length() }, 0);
            gl.glCompileShader(fragmentShader);
            gl.glGetShaderiv(fragmentShader, GL2.GL_COMPILE_STATUS, compiled, 0);
     
            // Ce n'est pas présent ici mais je vérifie bien évidemment la compilation de mes shaders avec gl.glGetShaderInfoLog
        }
     
        ...
     
        @Override
        public void display(GLAutoDrawable drawable) {
            GL2 gl = drawable.getGL().getGL2();
            gl.glClear(GL2.GL_DEPTH_BUFFER_BIT | GL2.GL_COLOR_BUFFER_BIT);
            gl.glEnable(GL2.GL_BLEND);
            gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
     
            gl.glViewport(0, 0, largeurEcran, hauteurEcran);
            gl.glMatrixMode(GL2.GL_PROJECTION);
            gl.glLoadIdentity();
            glu.gluPerspective(45.0f, ratioEcran, nearClipping, farClipping);
            glu.gluLookAt(...);
            gl.glMatrixMode(GL2.GL_MODELVIEW);
            gl.glLoadIdentity();
     
            // Je boucle ici sur tous les éléments à afficher
            for (Element e : myElements) {
                gl.glAttachShader(shaderProgram, vertexShader);
                gl.glAttachShader(shaderProgram, fragmentShader);
                gl.glLinkProgram(shaderProgram);
                gl.glValidateProgram(shaderProgram);
                gl.glUseProgram(shaderProgram);
     
                gl.glBindAttribLocation(shaderProgram, 0, "inPosition");
                gl.glBindAttribLocation(shaderProgram, 0, "inColor");
     
                int projectionHandler = gl.glGetUniformLocation(vertexShader, "projection");
                int viewHandler = gl.glGetUniformLocation(vertexShader, "view");
                int worldHandler = gl.glGetUniformLocation(vertexShader, "world");
                gl.glUniformMatrix4fv(projectionHandler, 1, false, projectionMatrix, 0);
                gl.glUniformMatrix4fv(viewHandler, 1, false, viewMatrix, 0);
                gl.glUniformMatrix4fv(worldHandler, 1, false, worldMatrix, 0);
     
                // 'toutesLesTextures' contient les textures chargées à partir du fichier XML qui contient ma scène 3D
                Texture texture = toutesLesTextures.get(element);
                texture.bind(gl);
                texture.enable(gl);
                gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST);
                gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
     
                // Ici, je génère un vertex buffer et un index buffer (je ne le détaille pas)
     
                gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
                gl.glEnableClientState(GL2.GL_COLOR_ARRAY);
                gl.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
     
                gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vertexBufferHandle);
                gl.glBufferData(GL2.GL_ARRAY_BUFFER, vertexBuffer.capacity() * Buffers.SIZEOF_FLOAT, vertexBuffer, GL2.GL_STATIC_DRAW);
                gl.glVertexPointer(3, GL.GL_FLOAT, Vertex.MEMORY_SIZE << 2, 0 << 2);
                // Est-ce que je devrais utiliser glVertexAttribPointer plutôt que glColorPointer ? Ou alors aucune différence ?
                gl.glColorPointer(4, GL.GL_FLOAT, Vertex.MEMORY_SIZE << 2, 6 << 2);
                gl.glTexCoordPointer(2, GL.GL_FLOAT, Vertex.MEMORY_SIZE << 2, 10 << 2);
     
                gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, indexBufferHandle);
                gl.glBufferData(GL2.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity() * Buffers.SIZEOF_INT, indexBuffer, GL2.GL_STATIC_DRAW);
     
                gl.glDrawElements(GL2.GL_TRIANGLES, indices.size(), GL2.GL_UNSIGNED_INT, 0);
     
                gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
                gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0);
     
                gl.glDisableClientState(GL2.GL_COLOR_ARRAY);
                gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
                gl.glDisableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
            }
     
            gl.glFlush();
     
            ...
        }
     
        @Override
        public void dispose(GLAutoDrawable drawable) {
            GL2 gl = drawable.getGL().getGL2();
            gl.glUseProgram(0);
            gl.glDetachShader(shaderProgram, vertexShader);
            gl.glDetachShader(shaderProgram, fragmentShader);
            gl.glDeleteShader(vertexShader);
            gl.glDeleteShader(fragmentShader);
            gl.glDeleteProgram(shaderProgram);
        }
    }
    Première question : j'ai mis un commentaire ci-dessus (ligne 83) concernant l'utilisation de glVertexAttribPointer / glColorPointer : quelle méthode dois-je utiliser ?
    Second question, très globale : la logique de mon code est-elle correcte ? (est-ce que j'appelle bien les bonnes fonctions et dans le bon ordre)
    Ensuite, troisième question : je vois bien comment se fait le lien entre mes matrices dans mon code Java et celle dans mes shaders via les appels successifs à gl.glGetUniformLocation et gl.glUniformMatrix4fv mais qu'en est-il de mes vertex ? J'ai bien appelé gl.glBindAttribLocation(shaderProgram, 0, "inPosition"); mais quand je fais un gl.glVertexPointer, je ne fais pas l'association avec le nom de variable "inPosition"... (???) C'est vraiment très flou pour moi de ce côté-là

    Pour information, voici le code source de mes shaders :
    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
     
    #version 400
     
    uniform mat4 world;
    uniform mat4 view;
    uniform mat4 projection;
     
    in vec3 inPosition;
    in vec4 inColor;
    out vec4 color;
     
    void main() {
        gl_Position = projection * view * world * vec4(inPosition, 1.0);
        // Si je décommente la ligne suivante, ça n'affiche plus rien, si je la laisse commentée, ma scène s'affiche correctement -> ???
        //color = vec4(1, 0, 0, 1);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    #version 400
     
    in vec4 color;
    out vec4 outColor;
     
    void main() {
        outColor = vec4(color);
    }
    En précision complémentaire, je travaille sous Windows 7 avec Eclipse Juno.

    Merci beaucoup d'avance pour votre aide et vos éclaircissements.
    Chen norris
    C/C++, C#, Java, PHP & SQL coder
    Web developer

  2. #2
    Membre actif Avatar de Chen norris
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2004
    Messages : 216
    Points : 248
    Points
    248
    Par défaut
    Bonsoir à tous,

    Je viens re-soulever un peu mon problème qui n'a malheureusement pas beaucoup avancé depuis la dernière fois. La seule chose dont je me suis rendu compte entre-temps est que glLink ne fonctionnait pas. N'ayant pas le détail de l'erreur dans les logs, je suis parti d'un exemple de shader trouvé sur le net, à savoir :

    Pour mon vertex shader :
    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
     
    #version 400
     
    uniform mat4 world;
    uniform mat4 view;
    uniform mat4 projection;
     
    in vec3 inPosition;
    in vec4 inColor;
     
    out vec4 color;
     
    void main() {
        gl_Position = projection * view * world * vec4(inPosition, 1.0);
        color = inColor;
    }
    Pour mon fragment shader :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    #version 400
     
    in vec4 color;
     
    out vec4 outputColor;
     
    void main() {
        outputColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
    Je suis vraiment allé au plus simple. Et déjà là, ça me pose problème car ça ne m'affiche rien du tout. Par contre, quand je commente la ligne du vertex shader gl_Position = projection * view * world * vec4(inPosition, 1.0);, je pense que ça applique un algorithme par défaut (algo évidemment correct) et du coup, je vois cette fois ma scène 3D s'afficher. Pouvez-vous me confirmer cette histoire d'algo par défaut ?

    Ensuite, savez-vous pourquoi quand je décommente je n'ai plus rien qui s'affiche ? Ma ligne est-elle syntaxiquement incorrecte / inefficace / ... ? Ou alors ce sont les matrices qui seraient mal initialisées ?
    Pour info, voici comment j'affecte les valeurs aux uniforms et aux variables in de mon vertex shader :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    // Setting the shader vertices' parameters
    gl.glBindAttribLocation(shaderProgram, 0, "inPosition");
    gl.glBindAttribLocation(shaderProgram, 1, "inColor");
     
    // Setting the shader's matrices
    int projectionHandler = gl.glGetUniformLocation(vertexShaderHandler, "projection");
    int viewHandler = gl.glGetUniformLocation(vertexShaderHandler, "view");
    int worldHandler = gl.glGetUniformLocation(vertexShaderHandler, "world");
    gl.glUniformMatrix4fv(projectionHandler, 1, false, CameraManager.getProjectionMatrix(), 0);
    gl.glUniformMatrix4fv(viewHandler, 1, false, CameraManager.getViewMatrix(), 0);
    gl.glUniformMatrix4fv(worldHandler, 1, false, CameraManager.getWorldMatrix(), 0);
    Ce code vous paraît-il correct ? Est-ce normal que je n'utilise pas le fragmentShaderHandler quelque part dans ces quelques lignes ?

    Beaucoup d'interrogations dans un domaine encore assez flou pour le moment pour moi.
    Merci d'avance pour votre aide.



    EDIT : ajout d'infos complémentaires concernant les matrices.
    Voici à quoi ressemblent mes matrices :

    Matrice de projection projection :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    1.299038, 0.0,             0.0,  0.0
    0.0,      1.7320509,       0.0,  0.0
    0.0,      0.0,       -1.002002, -1.0
    0.0,      0.0,       -2.002002,  0.0
    que je calcule comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Matrix4 projectionMatrix = new Matrix4();
    projectionMatrix.makePerspective(((float) Math.toRadians(fieldOfView)), aspectRatio, nearClipping, farClipping);
    Matrice de vue view
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    1.0, 0.0, 0.0, 0.0
    0.0, 1.0, 0.0, 0.0
    0.0, 0.0, 1.0, 0.0
    0.0, 0.0, 0.0, 1.0
    que je calcule via FloatUtil.makeIdentity pour avoir une matrice identité.

    Matrice du monde world
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    1.0, 0.0, 0.0, 0.0
    0.0, 1.0, 0.0, 0.0
    0.0, 0.0, 1.0, 0.0
    0.0, 0.0, 0.0, 1.0
    qui est aussi la matrice identité, mais multiplié par le zoom de la caméra. J'ai un petit doute sur ce que doit valoir la matrice World, peut-être est-ce là mon problème…
    Chen norris
    C/C++, C#, Java, PHP & SQL coder
    Web developer

  3. #3
    Membre actif Avatar de Chen norris
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2004
    Messages : 216
    Points : 248
    Points
    248
    Par défaut On avance... mais ce n'est toujours pas encore résolu
    Un peu de nouveau aujourd'hui : ayant toujours sous la main mon ancien projet en C#, j'ai affiché dans les logs les matrices World, View et Projection que j'y utilise et qui fonctionnent. En les comparant à celle de mon projet en Java, j'ai confirmation qu'il y a bien un problème sur le calcul d'une matrice (sauf qu'il s'agit de la matrice View, la matrice World étant en fait correcte). Après de nouvelles recherches sur le net, j'ai fini par trouver la formule de calcul qui va bien. Cette fois, c'est bon, j'ai des matrices identiques entre mon projet C# qui fonctionne et mon projet Java… qui n'affiche toujours rien Enfin si : il semble m'afficher quelque chose pendant une fraction de seconde puis ça devient vide. Si vous avez des idées sur l'origine de ce nouveau problème, je suis preneur.
    Chen norris
    C/C++, C#, Java, PHP & SQL coder
    Web developer

  4. #4
    Membre actif Avatar de Chen norris
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2004
    Messages : 216
    Points : 248
    Points
    248
    Par défaut
    Un an après environ, je reviens sur le sujet que j'avais quelques peu laissé de côté mais que j'ai récemment débloqué grâce à cette entrée de blog :
    http://miksblog.capcaval.org/2013/07/jogl-gl3-sample/

    Mes matrices n'étaient donc pas la source de mon problème, cela venait plutôt du fait que je me basais sur OpenGL 2, version pour laquelle les paramètres des shaders sont fixes. On passe alors par des variables pré-existantes comme gl_Position, gl_FragColor, … pour envoyer des informations aux shaders. Cela implique de connaître la correspondance entre cette liste de variables côté GLSL et les constantes associées côté Java pour envoyer l'information. Un autre incovénient est que l'on est limité dans la liste des informations que l'on souhaite transmettre aux shaders.
    Ce n'est qu'avec la version 3 d'OpenGL qu'arrivent les attributs et uniforms (pour ne parler que d'OpenGL, je ne m'attarderai pas sur le cas de DirectX). Le revers de la médaille, c'est qu'il faut obligatoirement passer par des buffers pour le rendu des objets. Pas mal de tutos expliquent en quoi cela consiste et comment le mettre en place, je ne le détaillerai pas beaucoup non plus, si ce n'est qu'il faut désormais bien respecter la procédure suivante :

    Lors de l'initialisation :
    • Déclarer l'objet à rendre (positions de vertex, couleurs, …),
    • Générer puis remplir les buffers associés avec les informations de l'objet.

    Ce n'est que dans un second temps, dans la boucle de rendu, que l'on peut procéder à l'envoi des buffers vers la mémoire graphique. Je résume très succintement (et peut-être maladroitement) la méthode mais pour ceux qui souhaiteraient une doc plus complète sur tout ça, je renvoie vers cet excellent tuto :
    http://bakura.developpez.com/tutorie...ec-opengl-3-x/

    Troisième endroit où j'ai trouvé de très bonnes infos : youtube. Je n'ai pas le lien de la chaîne sous la main mais vous pouvez la retrouver avec les mots clefs "OpenGL 3D Game tutorial". Chaque vidéo présente un aspect de la programmation 3D avec OpenGL, je conseille vivement leur visionnage car même si elles sont en anglais, les explications y sont très claires et très visuelles.

    Pour finir, je note donc mon post comme résolu sans aller plus loin dans les détails mais si quelqu'un souhaite davantage d'informations techniques sur comment je procède désormais, qu'il n'hésite pas à poster ici sa demande je prendrai volontiers le temps soit de transmettre les liens qui m'ont servi, soit de poster des explications sur la mécanique que je suis.
    À terme, je verrai si je ne transformerai d'ailleurs pas ce post en tuto en fonction de son succès.
    Chen norris
    C/C++, C#, Java, PHP & SQL coder
    Web developer

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Utilisation de curseurs personnalisés
    Par khayyam90 dans le forum Contribuez
    Réponses: 0
    Dernier message: 04/01/2011, 15h24
  2. [JOGL]utiliser la souris pour déplacer un élément
    Par GLDavid dans le forum OpenGL
    Réponses: 5
    Dernier message: 04/09/2009, 14h47
  3. [JOGL+GLSL] Fragment shader et sample2D
    Par xion.luhnis dans le forum OpenGL
    Réponses: 4
    Dernier message: 21/05/2009, 03h10
  4. Utilisation des types personnalisés
    Par juccuj dans le forum SQL
    Réponses: 1
    Dernier message: 31/07/2008, 16h13
  5. [Java3D] Comment utiliser des shaders ARB ?
    Par Knightmare dans le forum 3D
    Réponses: 1
    Dernier message: 25/05/2007, 12h05

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