PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Object-Auswahl mit der Maus in OpenGL



DanDanger
08-11-2002, 18:15
Hi,



Mein Ziel ist, ein Programm zu schreiben, das dort, wo der User hinklickt,
eine Kugel erstellt.
Der Knackpunkt ist : Wenn der User an eine Stelle klickt, wo schon eine Kugel
ist, so soll er die Object-ID der Kugel erfahren.

Ich hab' mal das Red-Book dazu befragt, aber irgendwie funzt deren Lösung
nicht :-(

Na, ich Poste einfach mal meinen Source-Code :
(Ich hoffe, die Kommentare erleichtern das Lesen ein weinig)

------------------ Schnipp -----------------------------


#include "varaibles.h"


#define KugelRadius 0.1f // Radius der Kugel von "CreateSphere"
#define Max_Punktladungen 10 // Die Maximale Anzahl an Punktladungen


Punktladung P_Ladung[Max_Punktladungen] ; // Array von 10 Punktladungen
int Anzahl_Punktladungen = 0 ; // Zähler für "Verbrauchte" Ladungen

bool StackCreated = false ;

void RenderScene() {

// Da RenderScene() im main-Programm bei jedem Frame aufgerufen wird,
// gehe ich so sicher, das Der Stack nicht jedesmal gelöscht wird

if(!StackCreated) {
cout << "Create Stack..." ;

glInitNames() ;
glPushName(0) ;

StackCreated = true ;

cout << "...OK" << endl ;
}

// Die Abfragen dienen nur dazu, die Maximale Anzahl an Kugeln zu begrenzen
if (Anzahl_Punktladungen >= 1 ) {

// Für jede existierende Punktladung Rendern :
for(int i=1 ; i<= Anzahl_Punktladungen ; i++) {

// In der Funktion wird die Kugel erstellt :
CreateSphere(P_Ladung[i].PosX, P_Ladung[i].PosY, P_Ladung[i].Pos,
ZKugelRadius) ;

} ; // Ende for-Schleife
} ; // Ende if-Schleife

// Swap Buffers (Änderungen Sichtbar machen)
SDL_GL_SwapBuffers();


} ;

// Erstelle Kugel. Mittelpunkt in X,Y-Koord. Radius = "Radius"

void CreateSphere(float MittelpunktX, float MittelpunktY, float MittelpunktZ,
float Radius) {



// Zeiger auf neues Object (Kugel)
GLUquadricObj *Kugel = gluNewQuadric() ;

glLoadName(Anzahl_Punktladungen) ;
// So bekommt die Kugel, die als erste erstellt wurde, den Namen 1,
die zweite den Namen 2, usw.......

// Na ja, hier wird eben die Kugel erstellt :
glPushMatrix() ;
gluQuadricDrawStyle(Kugel, GLU_LINE) ; // Kugel als Wire-Frame darstellen
glTranslatef(MittelpunktX, MittelpunktY, MittelpunktZ) ; // Kugel an
Position(x,y,z) erstellen
glColor3ub(0, 255, 0) ; // Farbe zuweisen
gluSphere(Kugel, Radius, 15, 15) ; // Kugel in 15er Schritten erstellen
glPopMatrix();

// Matrix-Operation beendet
glEnd();

// Kugel-Object löschen und Speicher wieder freigeben
// Obwohl ich die Kugel lösche, beibt sie ja auf dem Stack erhalten
gluDeleteQuadric(Kugel) ;

} ;




void CreateObjectOnMousePosition(int PosX, int PosY, float PosZ) {

float PosX_f = (float)PosX ; // Explizieter Typecast :
float PosY_f = (float)PosY ; // benötigt für genauere OpenGL Koord.
float PosZ_f = PosZ ;

if(Anzahl_Punktladungen <= Max_Punktladungen) {

// Schrit 1 : Zähler um 1 erhöhen,
// es wurde ja eine neue Punktladung hinzugefügt !
Anzahl_Punktladungen++ ;

/*------------------------------------------
..........................................*/

CreateSphere(PosX_f, PosY_f, 0, KugelRadius);


} else // Ende if(Anzahl_Punktladungen...

{
cout << "Achtung : Maximale anzahl an Punktladungen ueberschritten !" << endl ;
}

}

// Gibt die ID des Objektes zurück, auf das geklickt wurde
int GetObjectID(int PosX, int PosY, int Screen_Width, int Screen_Hight) {

int Sicht_Koordinaten[4] = {0} ;
int GeklickteObjekte = 0 ;

// OpenGL speichert diverse Informationen (32 Stück)
// in das SelectBuffer[32] Array !
unsigned int SelectBuffer[32] = {0} ;
// OpenGL wandelt des SelectionBuffer nun in
// "was brauchbares" um...
glSelectBuffer(32, SelectBuffer) ;

// Diese Function speichert ein Rechteck (4 Kanten).
// Das Rechteck entspricht dem, was die Camera sieht...
glGetIntegerv(GL_VIEWPORT, Sicht_Koordinaten) ;

// Rendere (Update) nur den SELECT-Buffer
glRenderMode(GL_SELECT) ;

//glInitNames();
//glPushName(0) ;
// Wir Verlassen mit dieser Funktion den 3D Raum (Modelview)
// und Projezieren die 3D Koodinaten in den 2D Raum (Projection).
// Nun kann man die 2D Koordinaten der Mouse gegen die 3D Koordinaten
// der 3D-Welt checken...
glMatrixMode(GL_PROJECTION) ;



// Die Matrix auf einem Stack sichern, um die
// 3D darstellung nicht zu beeinflussen
glPushMatrix();



// Alle Matrizen mit Einheitsmatrix überschreiben
glLoadIdentity() ;

// Koordinaten Umwandeln... 5, 5 ist die grösse des Fensters, in dem
// sich Objekte aufhalten müssen, um erkannt zu werden
gluPickMatrix(PosX, Sicht_Koordinaten[3] - PosY, 5, 5, Sicht_Koordinaten) ;

gluPerspective(45.0f,(float)Screen_Width/(float)Screen_Hight,0.1f,150.0f);
// wieder von 2D nach 3D wechseln...
glMatrixMode(GL_MODELVIEW) ;

// Scene erneut Rendern...
RenderScene() ;

// Haben wir auf etwas geklickt ?
GeklickteObjekte = glRenderMode(GL_RENDER) ;
//cout << GeklickteObjekte << endl

glMatrixMode(GL_PROJECTION) ;

// 2D-Matrix vom Stack holen
glPopMatrix() ;

// Wieder alte 3D-Grafik und Ansicht wiederherstellen...
glMatrixMode(GL_MODELVIEW) ;


// Wenn auf mehr als ein Objekt geklickt wurde,
// soll das ausgewählt werden, welches am nächsten
// zur Camera steht => "Tiefeninformationen" aller
// angeklickten Objekte vergleichen...
// Das Objekt mit der "geringsten Tiefe" ist am
// nächsten zur Camera...
if(GeklickteObjekte > 0) {

unsigned int geringsteTiefe = SelectBuffer[1] ;

// Welches Object wurde angewählt ?
int GewaehltesObjekt = SelectBuffer[3] ;

// Alle gefundenen Objekte vergleichen
for(int i=0 ; i < GeklickteObjekte ; i++) {

// ist das i-te Objekt tiefer als das bisherige tiefste
// Objekt ???
if(SelectBuffer[(i * 4) + 1] < geringsteTiefe) {
// Wenn ja => geringsteTiefe = tiefe des i-ten Objektes
geringsteTiefe = SelectBuffer[(i * 4) + 1] ;

// "Tiefstes Objekt" = aktuelles (i-tes) Objekt
GeklickteObjekte = SelectBuffer[(i * 4) + 1] ;

} ; // Ende if(SelectBuffer...) Abfrage
} ; // Ende der for-Schleife
cout << "Objekt geklickt" << endl ;
return GeklickteObjekte ;

} ;
//Wurde ins leere geklickt => return 0 ;
return 0 ;

} ;

-------------------------------Schnapp-----------------------

Tja,
wenn ich nun das Programm starte, und 2 Kugeln erstelle, so
haben beide Kugeln den Wert 1 (alles andere = 0)


Wäre nett, wenn mir mal einer sagen könnte, warum das nicht funzt
(oder kennt jemand eine gute Deutschsprachige OpenGL NewsGroup ?) ?



Neugierige Grüsse
DanDanger

EDIT by anda_skoa: hab code Tags eingefügt

tkortkamp
08-11-2002, 18:33
Das fehlen der [code ]-Tags in deinem Posting macht es sehr schwer deinen Code zu lesen...

Könntest du den Code noch in [ code ]-Tags packen?

DanDanger
08-11-2002, 19:34
Na kalro,
also hier nochmal das genze in Code-Tags :



#include "varaibles.h"


#define KugelRadius 0.1f // Radius der Kugel von "CreateSphere"
#define Max_Punktladungen 10 // Die Maximale Anzahl an Punktladungen


Punktladung P_Ladung[Max_Punktladungen] ; // Array von 10 Punktladungen
int Anzahl_Punktladungen = 0 ; // Zähler für "Verbrauchte" Ladungen

bool StackCreated = false ;

void RenderScene() {

// Da RenderScene() im main-Programm bei jedem Frame aufgerufen wird,
// gehe ich so sicher, das Der Stack nicht jedesmal gelöscht wird

if(!StackCreated) {
cout << "Create Stack..." ;






glInitNames() ;
glPushName(0) ;

StackCreated = true ;

cout << "...OK" << endl ;
}

// Die Abfragen dienen nur dazu, die Maximale Anzahl an Kugeln zu begrenzen
if (Anzahl_Punktladungen >= 1 ) {

// Für jede existierende Punktladung Rendern :
for(int i=1 ; i<= Anzahl_Punktladungen ; i++) {

// In der Funktion wird die Kugel erstellt :
CreateSphere(P_Ladung[i].PosX, P_Ladung[i].PosY, P_Ladung[i].Pos,
ZKugelRadius) ;

} ; // Ende for-Schleife
} ; // Ende if-Schleife

// Swap Buffers (Änderungen Sichtbar machen)
SDL_GL_SwapBuffers();


} ;

// Erstelle Kugel. Mittelpunkt in X,Y-Koord. Radius = "Radius"

void CreateSphere(float MittelpunktX, float MittelpunktY, float MittelpunktZ,
float Radius) {



// Zeiger auf neues Object (Kugel)
GLUquadricObj *Kugel = gluNewQuadric() ;

glLoadName(Anzahl_Punktladungen) ;
// So bekommt die Kugel, die als erste erstellt wurde, den Namen 1,
die zweite den Namen 2, usw.......

// Na ja, hier wird eben die Kugel erstellt :
glPushMatrix() ;
gluQuadricDrawStyle(Kugel, GLU_LINE) ; // Kugel als Wire-Frame darstellen
glTranslatef(MittelpunktX, MittelpunktY, MittelpunktZ) ; // Kugel an
Position(x,y,z) erstellen
glColor3ub(0, 255, 0) ; // Farbe zuweisen
gluSphere(Kugel, Radius, 15, 15) ; // Kugel in 15er Schritten erstellen
glPopMatrix();

// Matrix-Operation beendet
glEnd();

// Kugel-Object löschen und Speicher wieder freigeben
// Obwohl ich die Kugel lösche, beibt sie ja auf dem Stack erhalten
gluDeleteQuadric(Kugel) ;

} ;


void CreateObjectOnMousePosition(int PosX, int PosY, float PosZ) {

float PosX_f = (float)PosX ; // Explizieter Typecast :
float PosY_f = (float)PosY ; // benötigt für genauere OpenGL Koord.
float PosZ_f = PosZ ;

if(Anzahl_Punktladungen <= Max_Punktladungen) {

// Schrit 1 : Zähler um 1 erhöhen,
// es wurde ja eine neue Punktladung hinzugefügt !
Anzahl_Punktladungen++ ;

/*------------------------------------------
..........................................*/

CreateSphere(PosX_f, PosY_f, 0, KugelRadius);


} else // Ende if(Anzahl_Punktladungen...

{
cout << "Achtung : Maximale anzahl an Punktladungen ueberschritten !" << endl ;
}

}

// Gibt die ID des Objektes zurück, auf das geklickt wurde
int GetObjectID(int PosX, int PosY, int Screen_Width, int Screen_Hight) {

int Sicht_Koordinaten[4] = {0} ;
int GeklickteObjekte = 0 ;

// OpenGL speichert diverse Informationen (32 Stück)
// in das SelectBuffer[32] Array !
unsigned int SelectBuffer[32] = {0} ;
// OpenGL wandelt des SelectionBuffer nun in
// "was brauchbares" um...
glSelectBuffer(32, SelectBuffer) ;

// Diese Function speichert ein Rechteck (4 Kanten).
// Das Rechteck entspricht dem, was die Camera sieht...
glGetIntegerv(GL_VIEWPORT, Sicht_Koordinaten) ;

// Rendere (Update) nur den SELECT-Buffer
glRenderMode(GL_SELECT) ;

//glInitNames();
//glPushName(0) ;
// Wir Verlassen mit dieser Funktion den 3D Raum (Modelview)
// und Projezieren die 3D Koodinaten in den 2D Raum (Projection).
// Nun kann man die 2D Koordinaten der Mouse gegen die 3D Koordinaten
// der 3D-Welt checken...
glMatrixMode(GL_PROJECTION) ;



// Die Matrix auf einem Stack sichern, um die
// 3D darstellung nicht zu beeinflussen
glPushMatrix();



// Alle Matrizen mit Einheitsmatrix überschreiben
glLoadIdentity() ;

// Koordinaten Umwandeln... 5, 5 ist die grösse des Fensters, in dem
// sich Objekte aufhalten müssen, um erkannt zu werden
gluPickMatrix(PosX, Sicht_Koordinaten[3] - PosY, 5, 5, Sicht_Koordinaten) ;

gluPerspective(45.0f,(float)Screen_Width/(float)Screen_Hight,0.1f,150.0f);
// wieder von 2D nach 3D wechseln...
glMatrixMode(GL_MODELVIEW) ;

// Scene erneut Rendern...
RenderScene() ;

// Haben wir auf etwas geklickt ?
GeklickteObjekte = glRenderMode(GL_RENDER) ;
//cout << GeklickteObjekte << endl

glMatrixMode(GL_PROJECTION) ;

// 2D-Matrix vom Stack holen
glPopMatrix() ;

// Wieder alte 3D-Grafik und Ansicht wiederherstellen...
glMatrixMode(GL_MODELVIEW) ;


// Wenn auf mehr als ein Objekt geklickt wurde,
// soll das ausgewählt werden, welches am nächsten
// zur Camera steht => "Tiefeninformationen" aller
// angeklickten Objekte vergleichen...
// Das Objekt mit der "geringsten Tiefe" ist am
// nächsten zur Camera...
if(GeklickteObjekte > 0) {

unsigned int geringsteTiefe = SelectBuffer[1] ;

// Welches Object wurde angewählt ?
int GewaehltesObjekt = SelectBuffer[3] ;

// Alle gefundenen Objekte vergleichen
for(int i=0 ; i < GeklickteObjekte ; i++) {

// ist das i-te Objekt tiefer als das bisherige tiefste
// Objekt ???
if(SelectBuffer[(i * 4) + 1] < geringsteTiefe) {
// Wenn ja => geringsteTiefe = tiefe des i-ten Objektes
geringsteTiefe = SelectBuffer[(i * 4) + 1] ;

// "Tiefstes Objekt" = aktuelles (i-tes) Objekt
GeklickteObjekte = SelectBuffer[(i * 4) + 1] ;

} ; // Ende if(SelectBuffer...) Abfrage
} ; // Ende der for-Schleife
cout << "Objekt geklickt" << endl ;
return GeklickteObjekte ;

} ;
//Wurde ins leere geklickt => return 0 ;
return 0 ;

} ;