Selektion: Unterschied zwischen den Versionen

Aus DGL Wiki
Wechseln zu: Navigation, Suche
(Neuer Artikel)
 
K (Hinweis: WäHrend)
 
(9 dazwischenliegende Versionen von 4 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
 
==Was ist das?==
 
==Was ist das?==
Die Selektion ist ein bestimmter Rendermodus von '''OpenGL'''. Im Selektionsmodus (der durch [[glRenderMode]] gesetzt wird) werden keine [[Fragment]]e erzeugt und auch keine Änderungen am [[Framebuffer]] durchgeführt. Anstelle dessen werden 4 Werte pro [[Primitive]]n in einen [[glSelectBuffer|Selektions Puffer]] geschrieben. Dieser Puffer muss schon vor dem Aufruf dieser Funktion erstellt worden sein.
+
Die Selektion ist ein bestimmter Rendermodus von '''OpenGL'''. Im Selektionsmodus (der durch [[glRenderMode]] gesetzt wird) werden keine [[Fragment]]e erzeugt und auch keine Änderungen am [[Framebuffer]] durchgeführt. Anstelle dessen werden 4 Werte pro sichtbaren [[Primitive]]n in einen [[glSelectBuffer|Selektions Puffer]] geschrieben. Dieser Puffer muss schon vor dem Aufruf dieser Funktion erstellt worden sein.
  
 
Die vier Werte die man pro Primitiven erhält sind:
 
Die vier Werte die man pro Primitiven erhält sind:
Zeile 17: Zeile 17:
 
Folgende Funktionen haben mit der Selektion zu tun:
 
Folgende Funktionen haben mit der Selektion zu tun:
  
[[glRenderMode]], [[glSelectBuffer]], [[glLoadName]], [[gluPickMatrix]]
+
[[glRenderMode]], [[glSelectBuffer]], [[glLoadName]], [[gluPickMatrix]], [[Picking]]
 +
 
 +
 
 +
==Hinweis==
 +
Während der Selektion muss die selbe Perspektive ([[gluPerspective]] oder [[glOrtho]]) gesetzt sein wie beim rendern der Ausgabe. Außerdem darf die Perspektive nicht verändert werden, da das Ergebnis sonst merkwürdig ausfallen würde. Ein setzen des Orthomoduses während einer Perspectivenausgabe führt zu eben solchen Problemen. Entweder das Eine oder das Andere.
 +
 
 +
{{Warnung|
 +
Es gibt offensichtlich ein Problem mit den nVidia-Treibern, das dafür sorgt, dass die Selektion die Darstellung massiv verlangsamt. Wenn es also darum geht, die Anwendung portabel zu machen, sollte man auf andere Methoden und nicht auf die OpenGL-Eigene Selektion zurückgreifen.}}
 +
 
 +
==Beispiele==
 +
 
 +
===Selektion in 2D (glOrtho)===
 +
Im OnShow meines Formulares erstelle ich den Kontext. Zum Initialisieren der Ansicht rufe ich die untere Methode auf:
 +
<source lang="pascal">procedure TForm1.FormResize(Sender: TObject);
 +
var
 +
  VP: array[0..1] of Integer;
 +
  newWidth, newHeight: Integer;
 +
begin
 +
  if (FInitialised) then begin
 +
    // Set the viewport for the OpenGL window
 +
    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, @VP);
 +
 
 +
    // Dont make the Window to large
 +
    newWidth :=  Min(VP[0], ClientWidth);
 +
    newHeight := Min(VP[1], Max(1, ClientHeight));
 +
 
 +
    // Viewport von OpenGL setzen
 +
    glViewport(
 +
      (ClientWidth div 2)  - (newWidth div 2),
 +
      (ClientHeight div 2) - (newHeight div 2),
 +
      newWidth,
 +
      newHeight);
 +
 
 +
    // Projection matrix
 +
    glMatrixMode(GL_PROJECTION);
 +
    glLoadIdentity();
 +
 
 +
    // Perspektive setzen
 +
    glOrtho(0, newWidth, newHeight, 0, -1, 1);
 +
 
 +
    // Modelview Matrix
 +
    glMatrixMode(GL_MODELVIEW);
 +
    glLoadIdentity();
 +
  end;
 +
end;</source>
 +
 
 +
Beim Zeichnen mache ich dann nichts weiter als:
 +
<source lang="pascal">var
 +
  Error: Cardinal;
 +
  RenderMode: Cardinal;
 +
begin
 +
  // Go to the model view matrix mode
 +
  glMatrixMode(GL_MODELVIEW);
 +
 
 +
  // Replaces the current matrix with the identity matrix
 +
  glLoadIdentity();
 +
 
 +
  // Clear the color and depth buffers
 +
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
 +
 
 +
  glGetIntegerv(GL_RENDER_MODE, @RenderMode);
 +
 
 +
  glPushName(0);
 +
  glLoadName(10);
 +
  // Zeichnen
 +
  glPopName;
 +
 
 +
  Error := glGetError;
 +
  if Error <> 0 then
 +
    Caption := gluErrorString(Error);
 +
 
 +
  if (RenderMode = GL_RENDER)
 +
    then SwapBuffers (FDC);
 +
end;</source>
 +
 
 +
Die Selection sieht so aus:
 +
<source lang="pascal">var
 +
  Puffer      : array[0..256] of GLUInt;
 +
  Viewport    : TGLVectori4;
 +
  Treffer,i    : Integer;
 +
  Z_Wert      : GLUInt;
 +
  Getroffen    : GLUInt;
 +
begin
 +
  glGetIntegerv(GL_VIEWPORT, @viewport);
 +
  glSelectBuffer(256, @Puffer);
 +
  glRenderMode(GL_SELECT);
 +
 
 +
  glMatrixMode(GL_PROJECTION);
 +
  glPushMatrix;
 +
  glLoadIdentity;
 +
 
 +
  gluPickMatrix(X, Viewport[3] - Y, 1.0, 1.0, Viewport);
 +
  glOrtho(0, ClientWidth, ClientHeight, 0, -1, 1);
 +
 
 +
  FormPaint(Self);
 +
 
 +
  glMatrixMode(GL_PROJECTION);
 +
  glPopMatrix;
 +
 
 +
  treffer := glRenderMode(GL_RENDER);
 +
 
 +
  if treffer > 0 then begin
 +
    Getroffen := High(GLUInt);
 +
    Z_Wert := High(GLUInt);
 +
    for i := 0 to Treffer-1 do
 +
      if Puffer[(i*4)+1] < Z_Wert then begin
 +
        getroffen := Puffer[(i*4)+3];
 +
        Z_Wert := Puffer[(i*4)+1];
 +
      end;
 +
 
 +
    ShowMessage(IntToStr(Getroffen));
 +
  end;
 +
end;</source>
  
 
==Links==
 
==Links==
[http://www.delphigl.com/script/do_show.php?name=selection&action=2 Selektionstutorial bei DelphiGL.com]
+
[[Tutorial_Selection| Selektionstutorial von DelphiGL.com]]

Aktuelle Version vom 18. März 2012, 17:45 Uhr

Was ist das?

Die Selektion ist ein bestimmter Rendermodus von OpenGL. Im Selektionsmodus (der durch glRenderMode gesetzt wird) werden keine Fragmente erzeugt und auch keine Änderungen am Framebuffer durchgeführt. Anstelle dessen werden 4 Werte pro sichtbaren Primitiven in einen Selektions Puffer geschrieben. Dieser Puffer muss schon vor dem Aufruf dieser Funktion erstellt worden sein.

Die vier Werte die man pro Primitiven erhält sind:

  1. Anzahl der Namen auf dem Stack
  2. Kleinster Z-Wert des getroffenen Objektes
  3. Größter Z-Wert des getroffenen Objektes
  4. Name des Objektes

Wozu brauch ich das?

Für die Interaktion des Nutzers mit der Szene.

Wie geht das?

Durch den Selektionspuffer bekommt man die OpenGL Namen der Szenen Elemente zurückgeliefert die im Rendermodus GL_RENDER gerendert worden wären. Dies ermöglicht es unter zuhilfenahme von gluPickMatrix den Bereich um einen Mausklick auszuwerten. Wie das genau funktioniert könnt ihr im Selektionstutorial (siehe Links) nachlesen.

OpenGL Funktionen

Folgende Funktionen haben mit der Selektion zu tun:

glRenderMode, glSelectBuffer, glLoadName, gluPickMatrix, Picking


Hinweis

Während der Selektion muss die selbe Perspektive (gluPerspective oder glOrtho) gesetzt sein wie beim rendern der Ausgabe. Außerdem darf die Perspektive nicht verändert werden, da das Ergebnis sonst merkwürdig ausfallen würde. Ein setzen des Orthomoduses während einer Perspectivenausgabe führt zu eben solchen Problemen. Entweder das Eine oder das Andere.

Warnung.png

Es gibt offensichtlich ein Problem mit den nVidia-Treibern, das dafür sorgt, dass die Selektion die Darstellung massiv verlangsamt. Wenn es also darum geht, die Anwendung portabel zu machen, sollte man auf andere Methoden und nicht auf die OpenGL-Eigene Selektion zurückgreifen.

Beispiele

Selektion in 2D (glOrtho)

Im OnShow meines Formulares erstelle ich den Kontext. Zum Initialisieren der Ansicht rufe ich die untere Methode auf:

procedure TForm1.FormResize(Sender: TObject);
var
  VP: array[0..1] of Integer;
  newWidth, newHeight: Integer;
begin
  if (FInitialised) then begin
    // Set the viewport for the OpenGL window
    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, @VP);

    // Dont make the Window to large
    newWidth :=  Min(VP[0], ClientWidth);
    newHeight := Min(VP[1], Max(1, ClientHeight));

    // Viewport von OpenGL setzen
    glViewport(
      (ClientWidth div 2)  - (newWidth div 2),
      (ClientHeight div 2) - (newHeight div 2),
      newWidth,
      newHeight);

    // Projection matrix
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // Perspektive setzen
    glOrtho(0, newWidth, newHeight, 0, -1, 1);

    // Modelview Matrix
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
  end;
end;

Beim Zeichnen mache ich dann nichts weiter als:

var
  Error: Cardinal;
  RenderMode: Cardinal;
begin
  // Go to the model view matrix mode
  glMatrixMode(GL_MODELVIEW);

  // Replaces the current matrix with the identity matrix
  glLoadIdentity();

  // Clear the color and depth buffers
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

  glGetIntegerv(GL_RENDER_MODE, @RenderMode);

  glPushName(0);
  glLoadName(10);
  // Zeichnen
  glPopName;

  Error := glGetError;
  if Error <> 0 then
    Caption := gluErrorString(Error);

  if (RenderMode = GL_RENDER)
    then SwapBuffers (FDC);
end;

Die Selection sieht so aus:

var
  Puffer       : array[0..256] of GLUInt;
  Viewport     : TGLVectori4;
  Treffer,i    : Integer;
  Z_Wert       : GLUInt;
  Getroffen    : GLUInt;
begin
  glGetIntegerv(GL_VIEWPORT, @viewport);
  glSelectBuffer(256, @Puffer);
  glRenderMode(GL_SELECT);

  glMatrixMode(GL_PROJECTION);
  glPushMatrix;
  glLoadIdentity;

  gluPickMatrix(X, Viewport[3] - Y, 1.0, 1.0, Viewport);
  glOrtho(0, ClientWidth, ClientHeight, 0, -1, 1);

  FormPaint(Self);

  glMatrixMode(GL_PROJECTION);
  glPopMatrix;

  treffer := glRenderMode(GL_RENDER);

  if treffer > 0 then begin
    Getroffen := High(GLUInt);
    Z_Wert := High(GLUInt);
    for i := 0 to Treffer-1 do
      if Puffer[(i*4)+1] < Z_Wert then begin
        getroffen := Puffer[(i*4)+3];
        Z_Wert := Puffer[(i*4)+1];
      end;

    ShowMessage(IntToStr(Getroffen));
  end;
end;

Links

Selektionstutorial von DelphiGL.com