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

OpenGL Discussion :

Problème de Color Picking


Sujet :

OpenGL

  1. #1
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut Problème de Color Picking
    Bonjour tout le monde.
    J'ai un ensemble de données regroupées en cellules.
    Chaque cellule contiennent au moins un polygone (des tétras dans le majeur des cas).
    Je souhaite mettre en place un color picking. La sélection s'effectuerait en fonction des cellules.
    Pour cela, j'ai créé une couleur unique par cellule:
    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
    116
    117
    118
    119
    120
    121
    122
    package elements.colors;
     
    public class UniqueColorID {
            public static short MAX_NB_COLOR = 255;
    	public static byte MIN_BYTE_VALUE = Byte.MIN_VALUE;
    	public static byte MAX_BYTE_VALUE = Byte.MAX_VALUE;
     
    	private static short[] currentColorId = {0,0,0,MAX_NB_COLOR};
     
    	private static byte[] currentByteColorId = {MIN_BYTE_VALUE, MIN_BYTE_VALUE, MIN_BYTE_VALUE, MIN_BYTE_VALUE};
     
    	private byte[] colorByteId = new byte[4];
     
    	public UniqueColorID() {
    		colorByteId[0] = currentByteColorId[0];
    		colorByteId[1] = currentByteColorId[1];
    		colorByteId[2] = currentByteColorId[2];
    		colorByteId[3] = currentByteColorId[3];
    		updateCurrentByteColorId();
    	}
     
            //Met à jour le couleur courrante
            // Nous avons plus de 4 Milliards de possibilités
    	private void updateCurrentByteColorId() {
                    //Ajoute + 1 au rouge
    		currentByteColorId[0]++;
     
                    //Si le rouge est supérieur au MAX_BYTE_VALUE
    		if(currentByteColorId[0] >= MAX_BYTE_VALUE) {
                            //On réinitialise le rouge et on ajoute +1 au vert
    			currentByteColorId[0] = MIN_BYTE_VALUE;
    			currentByteColorId[1]++;
                            //Si le vert est supérieur au MAX_BYTE_VALUE
    			if(currentByteColorId[1] >= MAX_BYTE_VALUE) {
                                    //On réinitialise le vert et on ajoute +1 au bleu
    				currentByteColorId[1] = MIN_BYTE_VALUE;
    				currentByteColorId[2]++;
                                    //Si le bleu est supérieur au MAX_BYTE_VALUE
    				if(currentByteColorId[2] >= MAX_BYTE_VALUE) {
                                            //On réinitialise le bleu et on ajoute +1 au alpha
    					currentByteColorId[2] = MIN_BYTE_VALUE;
    					currentByteColorId[3]++;
                                            //Si le canal alpha est supérieur au MAX_BYTE_VALUE
    					if(currentByteColorId[3] >= MAX_BYTE_VALUE) {
                                                     //On réinitialise le canal alpha
    						currentByteColorId[3] = MIN_BYTE_VALUE;
    					}							
    				}
    			}
    		}
    	}
     
    	public byte[] getByteColorId() {
    		return colorByteId;
    	}
     
    	public byte getByteRedId() {
    		return colorByteId[0];
    	}
     
    	public byte getByteGreenId() {
    		return colorByteId[1];
    	}
     
    	public byte getByteBlueId() {
    		return colorByteId[2];
    	}
     
    	public byte getByteAlphaId() {
    		return colorByteId[3];
    	}
     
            //Récupère l'index associé à la couleur
    	public static int getIndexFromUniqueColorID(short[] pixel) {
    		int index = -1;
    		if(pixel != null && pixel.length == 4) {
    			index = (pixel[0] + (MAX_NB_COLOR*pixel[1] + pixel[1]) +
    					(MAX_NB_COLOR*pixel[2] + pixel[2]) +
    					(MAX_NB_COLOR*(pixel[3]-MAX_NB_COLOR/2) + (pixel[3]-MAX_NB_COLOR/2)));
    		}
    		return index;
    	}
     
    	public static int getIndexFromUniqueColorID(byte[] pixel) {
    		int index = -1;
    		if(pixel != null && pixel.length == 4) {
    			short[] pix = new short[4];
     
                            //Transforme un tableau de byte en un tableau short.
    			for(int i = 0; i<pixel.length; i++) {
    				if(pixel[i] >= 0)
    					pix[i] = pixel[i];
    				else
    					pix[i] = (short) (pixel[i] + 128);
    			}
    			return getIndexFromUniqueColorID(pix);
    		}
    		return index;
    	}
     
    	public static int getIndexFromUniqueColorID(byte red, byte green, byte blue, byte alpha) {
    		byte[] pixel = {red, green, blue, alpha};
    		return getIndexFromUniqueColorID(pixel);
    	}
     
            //Créer un tableau de fausses couleurs
    	public static byte[] buildByteColorIds(int sizeBuffer) {
    		int i = 0;
    		byte[] colorsId = new byte[sizeBuffer*4];
    		UniqueColorID colorId;
    		int index = 0;
    		while(i<sizeBuffer) {
    			colorId = new UniqueColorID();
    			colorsId[index++] = colorId.getByteRedId();
    			colorsId[index++] = colorId.getByteGreenId();
    			colorsId[index++] = colorId.getByteBlueId();
    			colorsId[index++] = colorId.getByteAlphaId();
    			i++;
    		}
    		return colorsId;
    	}
    }
    Pour information je suis en java donc on peut oublier les unsigned char... De plus j'utilise la bibliothèque LWJGL 2.5.

    Pour appliquer le tableau de fausses couleurs je le fais de la manière suivante:

    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
     
       private int initDisplayList() {
    	ArrayList<Vertex3D> vertices;
            //Le tableau de fausses couleurs
    	byte[] colorsId = UniqueColorID.buildByteColorIds(loader.getNbCells());
    	int indexId = 0;
     
    	int res = GL11.glGenLists(1);
     
    	GL11.glNewList(res, GL11.GL_COMPILE);
     
    	GL11.glDisable(GL11.GL_LIGHTING);
     
    	GL11.glBegin(GL11.GL_TRIANGLES);
    	GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
            //Pour chaque cellules
    	for (Cell c : CellManagement.getCells()) {
                //On applique une fausse couleur unique pour tous les polygones de la cellule
    	    GL11.glColor4ub(colorsId[indexId++], colorsId[indexId++],
    		    colorsId[indexId++], colorsId[indexId++]);
    	    for (Polygon3D e : c.getAllPolygon3D()) {
    		vertices = e.getVertexList();
     
    		int index = 1;
    		for (Vertex3D v : vertices) {
    		    GL11.glVertex3d(v.getX(), v.getY(), v.getZ());
    		    index++;
    		}
    	    }
    	}
    	GL11.glEnd();
    	GL11.glEnable(GL11.GL_LIGHTING);
    	GL11.glEndList();
     
    	return res;
        }
    Maintenant que j'ai ma display list de mon modèle en fausse couleur, il suffit d'utiliser la fonction glReadPixels qui permet de récupérer des informations sur un ou plusieurs pixels à proximité d'une zone donnée:

    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
     
    public void picking() {
    	GL11.glPushMatrix();
    	GL11.glMatrixMode(GL11.GL_MODELVIEW);
    	GL11.glLoadIdentity();
            //Remplie la matrice GL_MODELVIEW avec le modèle de fausses couleurs
    	GL11.glCallList(modelDisplayList);
     
    	GL11.glFlush();
     
    	IntBuffer viewport = BufferUtils.createIntBuffer(16);
     
            //Récupère le viewport
    	GL11.glGetInteger(GL11.GL_VIEWPORT, viewport);
     
    	ByteBuffer pixels = BufferUtils.createByteBuffer(40);
    	GL11.glDisable(GL11.GL_LIGHTING);
    	GL11.glEnable(GL11.GL_FLAT);
    	GL11.glDisable(GL11.GL_BLEND);
     
            //Récupère la couleur de pixel associé à la position MouseX et MouseY (corrigé par la hauteur de la fenètre)
    	GL11.glReadPixels(mouseListener.prevMouseX, viewport.get(3)
    		- mouseListener.prevMouseY, 1, 1, GL11.GL_RGBA,
    		GL11.GL_UNSIGNED_BYTE, pixels);
     
    	System.out.println("pixel[r,g,b,a] : " + pixels.get(0) + ", "
    		+ pixels.get(1) + ", " + pixels.get(2) + ", " + pixels.get(3));
     
    	// pixel in background?
    	if (pixels.get(0) == -1 && pixels.get(1) == -1 && pixels.get(2) == -1
    		&& pixels.get(3) == -1) {
    	    System.out.println("Background");
    	} else {
                //Récupère l'index de la cellule
    	    int index = UniqueColorID.getIndexFromUniqueColorID(pixels.get(0),
    		    pixels.get(1), pixels.get(2), pixels.get(3));
    	    System.out.println("Cell " + index + ": " +
    	    loader.getCellList().getCell(index));
    	    }
    	}
     
    	GL11.glEnable(GL11.GL_LIGHTING);
    	GL11.glDisable(GL11.GL_FLAT);
    	GL11.glEnable(GL11.GL_BLEND);
     
    	mouseListener.pickingMode = false;
    	GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
    	GL11.glPopMatrix();
    	GL11.glFlush();
        }

    Voici maintenant mon problème: lorsque je clique sur une des faces d'un tétra (qui appartient à une cellule), parfois il sélectionne un autre tétra ou trouve que c'est l'arrière plan.
    Je ne vois pas pourquoi dans certains cas mon picking ne fonctionne pas correctement...
    Avez-vous des idées?

    Merci d'avance

    PS: Si vous voulez le code en entier je peux vous l'envoyer en PM


    Edit:
    J'ai trouvé une erreur: lors de la lecture du pixel, j'ai une valeur de la couleur différente de celle passer dans la displaying list (notamment la valeur du canal alpha).

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    318
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 318
    Points : 291
    Points
    291
    Par défaut
    Je te conseille d'enregistrer ton rendu avec tes couleurs de picking dans une texture afin de voir si tu as vraiment les bonnes couleurs au bon endroit.

  3. #3
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Merci pour ta réponse mais je ne suis pas très familier avec les textures...
    Si je comprends bien je dois créer un tableau 1D qui correspond à mes textures, ensuite remplir le buffer de texture (GL_TEXTURE_2D) puis, pour chaque polygone, appliquer la texture associée (avec glTextCoord2d?).
    Si c'est le cas je ne pense pas que mes couleurs soient mal appliquées.
    J'ai vérifier en tentant d'afficher les valeurs des couleurs passées en paramètres de glColor4ub et j'obtiens les valeurs souhaitées (par exemple mon premier polygone aura la couleur -128,-128,-128,-128). Malheureusement, lors de la récupération des infos à l'aide de glReadPixel sur le premier polygone, j'obtiens -128,-128,-128,-1...
    Est-ce dû à un problème de glReadPixel et le canal alpha?

  4. #4
    Membre actif Avatar de Robxley
    Homme Profil pro
    Docteur ingénieur traitement d'image
    Inscrit en
    Mai 2009
    Messages
    158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Docteur ingénieur traitement d'image

    Informations forums :
    Inscription : Mai 2009
    Messages : 158
    Points : 228
    Points
    228
    Par défaut
    Coucou

    Il y a plus simple que de créer une texture pour vérifier l'état de tes couleurs.

    Tu affiche tout simplement le résultat de ta scène colorée servant au picking et tu regardes ce que ça donne (bien sur tu désactives ta vraie scène histoire de pas tout mélanger). Ça évite de créer une texture inutilement.

    Si non pour le canal Alpha je pense que ce n'est pas une bonne idée de l'utiliser n'étant pas une valeur "chromatique" mais de mélange. Il y a des risque de mélange des couleurs les unes avec les autres, ce qui pose justement souvent problème pour le color picking qui doit à tout pris conserver les vrais valeurs des couleurs.

    Et puis 3 canal qui vont de 0 à 255 ca fait suffisamment assez de combinaison pour ce que peux afficher les cartes graphiques en nombre d'objet. Donc pourquoi ce compliquer à la gestion du canal alpha.
    Rien ne sert de courir, mieux vaut partir à point. Programmer aussi d'ailleurs.
    Surtout, mais surtout pas d’astuces !
    Pas de bras, pas de chocolat. Les deux mains sur le clavier.

  5. #5
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Merci pour vos réponses.
    J'ai déjà affiché la scène en utilisant juste les "fausses" couleurs du modèle et elles correspondent bien (j'ai fait un test sur 2 tétra avec un en bleu l'autre en rouge). Mais j'obtiens le même résultat...

    Edit: J'ai changé ma méthode de picking par la méthode "classique" avec gluPickMatrix. J'avais un autre problème causer par la profondeur du récupérer par gluPickMatrix du binding LWJGL (version 2.5). Pour remédier à cela, je récupère la valeur de la profondeur (minimale et/ou maximale) et j'applique un masque et un décalage binaire de la manière suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    //depthMin et la valeur minimale de profondeur.
    depthMin = (depthMin >> 8) & 0x00FFFFFF;

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

Discussions similaires

  1. Mise en place d'un algorithme de color picking
    Par GLDavid dans le forum OpenGL
    Réponses: 46
    Dernier message: 26/08/2008, 16h25
  2. problème de coloration de cellule
    Par frisou65 dans le forum Macros et VBA Excel
    Réponses: 8
    Dernier message: 21/08/2008, 09h48
  3. problème de coloration des cellules de string grid
    Par linda80 dans le forum Composants VCL
    Réponses: 2
    Dernier message: 31/12/2007, 11h57
  4. Problème de coloration de cellules dans un DBGrid
    Par amaurylerouxdelens dans le forum Delphi
    Réponses: 7
    Dernier message: 08/11/2006, 13h47
  5. Réponses: 4
    Dernier message: 28/08/2006, 17h11

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