#include <math.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <GL/gl.h>#include "SDL/SDL.h"#include "SDL/SDL_opengl.h"#define RENDER 1 // No ray-plane intersection (i haven't studied the vectors properly ) #define SELECT 2 // So old-good color selection#define MORPHOS 1#define SWITCH_INT(a) { char s_i, *p_i;p_i= (char *)&(a);s_i=p_i[0]; p_i[0]=p_i[3]; p_i[3]=s_i;s_i=p_i[1]; p_i[1]=p_i[2]; p_i[2]=s_i; }int mode = RENDER;int FRAMES_PER_SECOND = 50; //The frames per second constint frame = 0; //Keep track of the current frameint startTicks = 0;int currentTicks=0;int SCREENW=800;int SCREENH=600;int EDITORMODE=0; // old stuff from the editor 0=Add,1=Paint,2=Del,3=load,4=save,5=new,6=textureint OLDEDITORMODE=0; //int GRID=0; //int mousex,mousey;unsigned int nIndex;void DrawSelection() { glDisable(GL_LIGHTING); glDisable( GL_TEXTURE_2D ); nIndex=10000; glColor3ub ( nIndex % 256, (nIndex>>8) % 256, (nIndex>>16) % 256); glBegin(GL_QUADS); glVertex3f( -0.5f, -0.5f, +0.5f); glVertex3f( +0.5f, -0.5f, +0.5f); glVertex3f( +0.5f, +0.5f, +0.5f); glVertex3f( -0.5f, +0.5f, +0.5f); glEnd();}void mouseMove (int x, int y) { static int x_pos = 0; static int y_pos = 0; x_pos = x; y_pos = y;}void ProcessPick() { unsigned int col; GLint viewport[4]; glGetIntegerv(GL_VIEWPORT,viewport); glReadPixels( mousex, viewport[3]-mousey, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &col); SWITCH_INT(col); printf(" color number %un",nIndex); printf(" color founded %un",col); printf(" color put %u ,%u ,%un",nIndex%256,(nIndex>>8) % 256, (nIndex>>16) % 256); printf(" color get %u ,%u ,%un",col%256,(col>>8) % 256, (col>>16) % 256); }int main(int argc, char *argv[]) { SDL_Surface *screen; int done; SDL_Event event; Uint8* keystates; // Slightly different SDL initialization if ( SDL_Init(SDL_INIT_VIDEO| SDL_INIT_AUDIO) != 0 ) { printf("Unable to initialize SDL: %sn", SDL_GetError()); return 1; } SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new* screen = SDL_SetVideoMode( SCREENW, SCREENH, 32, SDL_OPENGL /*| SDL_FULLSCREEN*/); // *changed* if ( !screen ) { printf("Unable to set video mode: %sn", SDL_GetError()); return 1; } glViewport( 0, 0, SCREENW, SCREENH ); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, 1.0 * SCREENW/SCREENH, 0.1, 400.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable (GL_DEPTH_TEST); glEnable (GL_COLOR_MATERIAL); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gluLookAt(0,0,18,0.0,0.0,0.0,0.0,1.0,0.0); done=0; glClearColor( 0, 0, 0, 0); while(!done){ startTicks=SDL_GetTicks(); // Clear the screen before drawing glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); while(SDL_PollEvent(&event)) { switch (event.type) { case SDL_MOUSEMOTION: mouseMove (event.button.x, event.button.y); mousex=event.button.x; mousey=event.button.y; break; case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE) done=1; break; case SDL_MOUSEBUTTONDOWN : if (SDL_GetMouseState (NULL,NULL) & SDL_BUTTON_LMASK) { mousex=event.button.x; mousey=event.button.y; mode = SELECT; } break; default: break; } } if (mode == SELECT) DrawSelection(); else DrawSelection(); if (mode == SELECT) { ProcessPick(); mode = RENDER; } else SDL_GL_SwapBuffers(); if( currentTicks < 1000 / FRAMES_PER_SECOND ) SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - currentTicks ); } SDL_Quit(); return 0;}
Non l'ho debuggato perchè non ne ho il tempo, ma dando un'occhiata veloce al codice ed alla tua descrizione posso sicuramente notare un difetto di approccio da non trascurare.In sostanza vuoi effettuare il picking di un oggetto usando il colore che questo mostrerà in fase di rendering (in viewport space), mentre tu conosci solo il colore "originale" (cioè nell'object space).
vedo che hai usato questa orribile tecnica http://www.codeguru.com/Cpp/G-M/opengl/ ... .php/c5579in giro esistono altre guide ancora più oscene, che sfruttano il GL_SELECT. Beh, lasciamo stare... :-)
E' chiaro come il sole che la tecnica può funzionare solo se tutta la trafila utilizza un numero di bit sufficiente a non perdere informazioni per strada. In particolare, non è detto che internamente i colori siano sempre RGB24, ma possono anche scendere a RGB16 o RGB15 in base a vari meccanismi interni. Anche se tutta la trafila fosse comunque perfettamente calibrata come numero di bit per canale, potresti sempre avere a che fare con dei calcoli che introducono errori ed approssimazioni (in questo caso introduce un bias verso il nero).
Piuttosto che stare ad impazzire dietro alle conversioni di colore del driver GL di MorphOS (che magari potrebbe cambiare da versione a versione), devi implementare il picking in modo corretto. Come si fa? Con la proiezione inversa dallo schermo verso il World Space.- Prendi un pixel sulla viewport- lo moltiplichi per l'inversa della matrice di proiezione sul near plane e sul far clipping plane (trovandoti così 2 punti perpendicolari allo schermo)- prendi il vettore che unisce questi due punti ed effettua un test ray-box intersection per ciascun oggetto della scena (proiettando ogni volta il vettore di interezione per l'inversa della modelview di ogni oggetto)- prendi tutti gli oggetti così intersecati e ordinali in base alla distanza dal near plane[ passaggi opzionali se vuoi fare il picking con precisione al poligono ]- partendo dall'oggetto più vicino, moltiplica il vettore di prima per l'inversa della matrice di modelview di quell'oggetto, e ti ritrovi nell'object space.- effettua un test Ray-Triangle su ciascun triangolo (aiutati con un quadtree o, meglio ancora, con un modello scheletale se i tuoi modelli sono troppo carichi di poligoni)- se becchi almeno un triangolo hai trovato l'oggetto corretto.
link utili (presi più o meno a casaccio da Google) http://www.mt-wudan.com/wu_tut.php?t=gl_mouserayhttp://www.euclideanspace.com/threed/re ... /index.htmhttp://www.euclideanspace.com/maths/alg ... /index.htmhttp://eigenclass.blogspot.com/2008/10/ ... ngbox.htmlEnjoy!
Aspetta, forse c'è una soluzione più semplice, in base al tipo di lavoro che deve fare:ad esempio, sto scrivendo una specie di clone di Minecraft, e dato che il mondo è formato da cubi regolari, partendo dalla posizione del giocatore e dalla direzione in cui guarda, posso (con qualche algoritmo di rasterizzazione) trovare facilmente tutti i cubi presenti sulla linea dello sguardo.Bisognerebbe conoscere più in dettaglio lo scopo del programma, per trovare eventuali semplificazioni.
Bisognerebbe conoscere più in dettaglio lo scopo del programma, per trovare eventuali semplificazioni.
class RgbVector // {public: RgbVector(int r, int g, int b); int lenght2() const; // lunghezza quadrata RgbVector operator-(const RgbVector& a, const RgbVector& b); // operatore per la differenza int mR, mG, mB; // i 3 canali, pubblici per semplicita'}RgbVector::RgbVector(int r, int g, int b){ mR = r; mG = g; mB = b;}int RgbVector::length2() const{ return mR*mR + mG*mG + mB*mB;}RgbVector RgbVector::operator-(const RgbVector& a, const RgbVector& b){ return RgbVector(a.mR - b.mR, a.mG - b.mG, a.mB - b.mB);}
// Esempio, usando le variabili prese dal tuo codiceRgbVector coloreRiferimento(nIndex%256,(nIndex>>8) % 256, (nIndex>>16) % 256); RgbVector colorePixel(col%256, (col>>8) % 256, (col>>16) % 256)RgbVector differenza = coloreRiferimento - colorePixel;int tolleranza = 12; // sarebbe (2*2)+(2*2)+(2*2) quindi max 2 livelli di differenza per canaleif (differenza.length2() <= tolleranza){ // Ok, il colore e' simile abbastanza}else{ // Non ci siamo, il colore e' completamente diverso}
EDIT: avevo scritto una boiata perchè non avevo capito subito il tuo esempio... comunque, ecco la mia risposta corretta:
Nel tuo caso il picking è fatto all'interno del World Space, e il gioco segue una geometria semplice basata su una matrice bidimensionale. Nel tuo caso quindi si rimane a livello di Model.Qui si parla invece di prendere una scena 3D assolutamente generica e trovare quell'oggetto che sta sotto il pixel desiderato. In questo caso bisogna risalire al model partendo dalla view. Sono problemi del tutto differenti.