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:
Pour information je suis en java donc on peut oublier les unsigned char... De plus j'utilise la bibliothèque LWJGL 2.5.
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 appliquer le tableau de fausses couleurs je le fais de la manière suivante:
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 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; }
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).
Partager