2014-09-05 11 views
5

Sto implementando un grafico 2D in WPF utilizzando la libreria SharpGL. Sono riuscito a disegnare alcuni oggetti primitivi sullo schermo e ho bisogno di rilevare i clic del mouse su questi oggetti.SharpGL - Rilevamento dei clic del mouse sugli elementi OpenGL mediante selezione e prelievo

Ho dato un'occhiata a un tutorial OpenGL su come eseguire la selezione e il prelievo su oggetti grafici, ma non sono riuscito a farlo funzionare. Nella mia applicazione di prova disegno tre triangoli sullo schermo e quando si verifica un clic del mouse disegno gli stessi tre triangoli nella modalità GL_SELECT sperando di rilevare se uno qualsiasi dei triangoli è stato cliccato. Non sono sicuro se questo è l'approccio corretto. Hit test restituisce sempre tutti gli elementi dal buffer di selezione.

So che i parametri di larghezza e altezza in PickMatrix non sono corretti, e non sono veramente sicuro di quali sarebbero i valori corretti. È la larghezza e l'altezza dell'intera vista?

private void OpenGLControl_OpenGLDraw(object sender, SharpGL.SceneGraph.OpenGLEventArgs args) 
{ 
    //// Get the OpenGL object. 
    OpenGL gl = args.OpenGL; 

    //set background to white 
    gl.ClearColor(1.0f, 1.0f, 1.0f, 1.0f); 

    //// Clear the color and depth buffer. 
    gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); 
    DrawScene(); 
    gl.Flush(); 
} 

private void DrawScene() 
{ 
    OpenGL gl = openGLControl.OpenGL; 
    gl.Color(1.0, 0.0, 0.0); 
    DrawTriangle(-0.2, 0.6, 0.0, 0.8, 0.2, 0.6); 

    gl.Color(0.0, 1.0, 0.0); 
    DrawTriangle(-0.2, 0.2, 0.0, 0.4, 0.2, 0.2); 

    gl.Color(0.0, 0.0, 1.0); 
    DrawTriangle(-0.2, -0.2, 0.0, 0.0, 0.2, -0.2); 
} 

private void SelectObjects(double mouseDownX, double mouseDownY) 
{ 
    OpenGL gl = openGLControl.OpenGL; 
    int BUFSIZE = 512; 

    uint[] selectBuf = new uint[BUFSIZE]; 

    gl.SelectBuffer(BUFSIZE, selectBuf); 
    gl.RenderMode(OpenGL.GL_SELECT); 

    gl.InitNames(); 
    gl.PushName(0); 

    int[] viewport = new int[4]; 
    gl.GetInteger(OpenGL.GL_VIEWPORT, viewport); 

    //how to define the width and height of an element? 
    gl.PickMatrix(mouseDownX, (double)(viewport[3] - mouseDownY), 50.0, 50.0, viewport); 

    gl.LoadIdentity(); 

    gl.LoadName(1); 
    gl.Color(1.0, 0.0, 0.0); 
    DrawTriangle(-0.2, 0.6, 0.0, 0.8, 0.2, 0.6); 

    gl.LoadName(2); 
    gl.Color(0.0, 1.0, 0.0); 
    DrawTriangle(-0.2, 0.2, 0.0, 0.4, 0.2, 0.2); 

    gl.LoadName(3); 
    gl.Color(0.0, 0.0, 1.0); 
    DrawTriangle(-0.2, -0.2, 0.0, 0.0, 0.2, -0.2); 

    gl.Flush(); 
    int hits = gl.RenderMode(OpenGL.GL_RENDER); 
    processHits(hits, selectBuf); 
} 

private void processHits(int hits, uint[] buffer) 
{ 
    uint bufferIterator = 0; 
    for (uint i = 0; i < hits; i++) 
    { 
     uint numberOfNamesInHit = buffer[bufferIterator]; 
     Console.WriteLine("hit: " + i + " number of names in hit " + numberOfNamesInHit); 

     uint lastNameIndex = bufferIterator + 2 + numberOfNamesInHit; 
     for (uint j = bufferIterator + 3; j <= lastNameIndex; j++) 
     { 
      Console.WriteLine("Name is " + buffer[j]); 
     } 

     bufferIterator = bufferIterator + numberOfNamesInHit + 3; 
    } 
} 

private void OnMouseClick(object sender, MouseEventArgs e) 
{ 
    System.Windows.Point position = e.GetPosition(this); 
    SelectObjects(position.X, position.Y); 
} 

L'uscita è sempre la stessa:

successo: 0 numero di nomi a colpo 1

nome è 1

colpo: 1 numero di nomi a colpo 1

Nome è 2

h esso: 2 numero di nomi a colpo 1

Name è 3

risposta

3

larghezza e altezza sono le dimensioni della regione raccolta in pixel. Per rilevare oggetti sotto il puntatore del mouse, 1x1 dovrebbe andare bene (vuoi rilevare cosa c'è sotto un rettangolo dello schermo di 1 pixel per 1 pixel).

gluPickMatrix aggiornamento (moltiplica) la matrice corrente con la matrice di prelievo. Il tuo PickMatrix seguito da LoadIdentity non ha alcun senso, dal momento che glLoadIdentity reimposta la matrice corrente all'identità.

per il vostro campione per lavorare, prima di render, configurare il matrice:

glLoadIdentity(); 
setupMyProjMatrix(); 

Prima di selezionare, configurare la stessa matrice, pre-moltiplicato per la matrice scelta:

glLoadIdentity(); 
glPickMatrix(); 
setupMyProjMatrix(); 

nel campione , setupMyProjMatrix() non fa nulla.

In ogni caso, evitare di usare picking in opengl. È una funzionalità deprecata, (eliminata nella moderna versione gl), terribilmente lenta, ea volte non molto affidabile, a seconda dei fornitori. Dovresti calcolare da solo il test di successo.

Non si dovrebbe mai, mai interrogare qualcosa di gl (famiglia glGet). Provoca lo stallo della CPU.

Ci scusiamo per il cattivo inglese.

+0

Grazie per la spiegazione, ho eliminato la linea glLoadIdentitiy e ha funzionato bene :) – mobearette

2

Come già detto Olivier, evitare le funzionalità deprecate.Invece si può fare la raccolta in 2 modi diversi:

  • pick eseguendo tutti i poligoni orientati in avanti attraverso un raggio-test, in cui si lancia un raggio dall'occhio-point attraverso il centro di un pixel (a vicino distanza dell'aereo) fino a quando non colpisce un poligono o cade oltre l'intervallo di selezione. Questa soluzione non è adatta alle scene complesse, ma è piuttosto semplice da implementare e offre un certo grado di flessibilità per gestire la trasparenza ecc.

  • È anche possibile eseguire il prelievo nello spazio di visualizzazione eseguendo il rendering di tutti gli oggetti con un ID colore a una trama fuori schermo. È quindi possibile leggere semplicemente il valore del pixel della coordinata 2D selezionata e mappare l'identificativo del colore all'oggetto sotto quella coordinata di selezione. Il rovescio della medaglia qui è che il picking di più oggetti è più difficile e che il batch renderizzato deve avere impostazioni di culling e shading appropriate. Il vantaggio è che questa soluzione dipende dalla risoluzione e non dipende tanto dalla complessità della scena.

Problemi correlati