[openGL] Zwei Flächen nah beieinander



  • Hi,

    ich möchte zwei Flächen nah beieinander zeichnen. Die Flächen
    sollten eigentlich einfarbig sein, aber bekommen in diesem Fall
    eine komische Schraffierung. Gibt es eine Möglichkeit dies zu umgehen?
    Ich zeichne GL_QUAD_STRIP Elemente.

    Viele Grüße
    Tomatojuice



  • Wie sieht die Projectionsmatrix aus - bzw. sind zNear und zFar sinnvoll gewählt (davon ist die Genauigkeit des Tiefenpuffers bzw. der Werte abhängig).

    Welchen Parameter hast du glDepthFunc übergeben?



  • Die Werte die du genannt hast finde ich garnicht in meinem Projekt.
    Ich kenn mich mit OpenGL nicht so gut aus, aber fürs zeichnen hats bis jetzt
    eigentlich ganz gut gereicht ^^. Naja hier ist ein Auszug aus meiner
    Initialisierungsfunktion falls das was bringt:

    PIXELFORMATDESCRIPTOR pfd =
    {
        sizeof(PIXELFORMATDESCRIPTOR),    // size of this pfd
        1,                                // version number
        PFD_DRAW_TO_WINDOW |              // support window
        PFD_SUPPORT_OPENGL |              // support OpenGL
        PFD_DOUBLEBUFFER,                 // double buffered
        PFD_TYPE_RGBA,                    // RGBA type
        24,                               // 24-bit color depth
        0, 0, 0, 0, 0, 0,                 // color bits ignored
        0,                                // no alpha buffer
        0,                                // shift bit ignored
        0,                                // no accumulation buffer
        0, 0, 0, 0,                       // accum bits ignored
        32,                               // 32-bit z-buffer
        0,                                // no stencil buffer
        0,                                // no auxiliary buffer
        PFD_MAIN_PLANE,                   // main layer
        0,                                // reserved
        0, 0, 0                           // layer masks ignored
    };
    GLint  iPixelFormat;
    
    iPixelFormat = ChoosePixelFormat(hdc, &pfd);
    
    SetPixelFormat(hdc, iPixelFormat, &pfd);
    
    m_hglrc = wglCreateContext(m_hDC);
    
    wglMakeCurrent(hdc, m_hglrc);
    
    GLfloat ambientColor[] = {0.5f,0.5f,0.5f,1.0f};
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientColor);
    
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat mat_shininess[] = { 50.0 };
    
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f) ;
    glEnable(GL_NORMALIZE);
    glShadeModel(GL_SMOOTH);
    
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);							
    
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_DEPTH_TEST);
    
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
    glEnable(GL_COLOR_MATERIAL);
    

    Meine Flächen sind btw 0.001 auseinander.



  • Naja, irgendwo wirst du ja eine Projektionsmatrix erstellen, entweder per Hand (in Deinem Fall wohl eher unwahrscheinlich) oder durch den Aufruf von glOrtho, glFrustum, gluPerspective, gluOrtho2D etc.

    Dort gibst du unter anderem zNear und zFar an. Die Genauigkeit des Tiefenpuffers ist aber abhängig vom Verhältnis der beiden Werte. Also solltest du dort möglichst nicht sowas wie zNear = 0.0001 und zFar = 10000 verwenden.

    Über den Parameter von glDepthFunc gibt du an, wann Fragmente den Tiefentest (aktiviert mit glEnable(GL_DEPTH_TEST)) bestehen.



  • Danke schonmal! Jetzt kapier ich einiges mehr :).

    Also der Tiefenpuffer wird in meinem Code nicht verändert. Der sollte ja
    standardmäßig angeschaltet sein oder?

    Ich benutze alternativ die perspective und die orthogonal Projektion.

    Perspective hat folgende Parameter:
    60.0, B/H, 0.001, 6.0

    Bei Orthogonal werden ja lediglich die Sichtgrenzen eingegeben.

    Mit welchen Parametern bekomme ich jetzt bei den beiden Projektionen
    die bessere Tiefentreue hin?

    Hier die Projektionsfunktion:
    (OpenGL ist hier ein .net Panel-Objekt)

    // Clear the window for next redraw                
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);				
    
    // Höhe und Breite des Fensters in dem gezeichnet wird
    int w=OpenGL->Width,h=OpenGL->Height;
    glViewport (0,0,w,h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    
    // Kameraposition berechnen
    double a=cos(m_elevation);
    double x=(m_cameradist)*a*sin(m_azimuth);
    double y=(m_cameradist)*a*cos(m_azimuth);
    double z=-m_cameradist*sin(m_elevation);
    
    // In Perspektive oder orthogonal zeichnen
    if (rbtn_perspective->Checked)
    {
    gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 0.001, 6.0);
    }
    else if (rbtn_orthogonal->Checked)
    {
    glOrtho(-m_cameradist*((GLfloat) w/(GLfloat) h)*0.5,	//linke Sichtgrenze
        m_cameradist*((GLfloat) w/(GLfloat) h)*0.5,		//rechte Sichtgrenze
        -m_cameradist*0.5,	//untere Sichtgrenze
        m_cameradist*0.5,	//obere Sichtgrenze
       -40,	//hintere Sichtgrenze
       40);	//vordere Sichtgrenze
    }
    
    // Position und Ausrichtung der Kamera
    gluLookAt(x				//camposx
      , y			//camposy
      , z+0.07		//camposz
      , 0,0,0.07	//viewing centre
      , 0			//"up" directionx
      , 0			//"up" directiony
      , -1);			//"up" directionz
    
    // Licht bewegt sich mit Viewpoint
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    GLfloat light_position1[] = { (float)(x), (float)(y), (float)(z), 0.0 };
    glLightfv(GL_LIGHT0, GL_POSITION, light_position1);
    
    // Drehen nach den entsprechenden Controls
    glRotated(Convert::ToDouble(num_AngleX->Value), 1, 0, 0);
    glRotated(Convert::ToDouble(num_AngleY->Value), 0, 1, 0);
    glRotated(Convert::ToDouble(num_AngleZ->Value), 0, 0, 1);
    
    // Translation des Modells durch die entsprechenden Slider
    glTranslated(((double)Slider_x_AchsenOffset->Value)/100,((double)Slider_y_AchsenOffset->Value)/100, ((double)Slider_z_AchsenOffset->Value)/100);
    
    // Alle Komponenten zeichnen
    for (int i = 0; i < m_Components->Count; i++)
    {
    m_Components[i]->Render();
    }
    
    // Achsen zeichnen
    glDisable(GL_LIGHTING);
    
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    glBegin(GL_LINES);
    glColor3d (1,0,0);
    glVertex3d(0,0,0);
    glVertex3d(1,0,0);
    
    glColor3d (0,1,0);
    glVertex3d(0,0,0);
    glVertex3d(0,1,0);
    
    glColor3d (0,0,1);
    glVertex3d(0,0,0);
    glVertex3d(0,0,1);
    glEnd();
    
    glEnable(GL_LIGHTING);
    
    // Neue Zeichnung anzeigen
    SwapBuffers(m_hDC);
    


  • Nein, das depth-testing ist nicht standardmäßig aktiviert.
    Wie gesagt erfolgt dies über glEnable(GL_DEPTH_TEST).

    Du könntest mal probieren, den Wert für zNear von 0.001 auf 0.01 zu ändern. Vlt führt dies ja schon zum Erfolg.



  • Wenn es zur Platzierung von Near und Far Plane kommt dann gibts eine Grundregel: Near so weit weg und Far so nahe dran wie nur möglich um den Depthbuffer optimal zu nutzen. Ich bin mir ziemlich sicher dass es sich bei dem was du beschreibst um z-Fighting handelt...



  • Kannst du mal einen Screenshot posten der diese "Schraffierung" zeigt?



  • So ich hab mal nen Screenshot gemacht:

    http://img88.imageshack.us/img88/4110/schraffierung.jpg

    Man sieht die Perspective Projection. Links etwas weiter entfernt, rechts
    ziemlich nah dran. Die Pfeile hab ich an den Stellen reingezeichnet, wo
    ein neues paar Rechteckecke übereinander gezeichnet wird.
    Interessant ist, dass bei der kurzen Entfernung und perspektivischen Sicht
    die Schraffierung verschwindet.
    Bei beiden Projektionen verschwindet die Schraffierung, wenn man in einem
    Winkel von etwas über 45° auf die Fläche blickt.
    Die Normalenvektoren der übereinanderliegenden Rechtecke zeigen übrigens in
    entgegengesetzte Richtungen.
    UND: die Schraffierung sieht man nur von einer Seite...

    any ideas?
    GL_Depth_Test war übrigens doch eingeschaltet (siehe Z. 48 vom Code). Könnte
    es evtl. noch an den anderen Einstellungen liegen die dort vorgenommen werden?


  • Mod

    Tomatojuice schrieb:

    any ideas?

    dot hat das eindeutig auf den punkt gebracht:

    dot schrieb:

    Ich bin mir ziemlich sicher dass es sich bei dem was du beschreibst um z-Fighting handelt...

    und inter2k3 die frage deren antwort zu deiner loesung fuehren wird.



  • okay, also ich hab jetzt mal ein wenig mit near und far rumgespielt.
    Ich bekomms so hin, dass es nicht mehr flimmert, aber er schneidet schon
    sehr sehr früh den Vordergrund weg.

    Bei Orthogonaler Sicht hab ich ja garkein znear oder zfar. Kennt jemand
    dafür andere Parameter?

    Übrigens wenn ich die GlDepthFunc auf GL_LESS stelle macht die eine Seite
    Probleme, bei GL_LEQUAL die andere.
    Also müsste es doch theoretisch etwas geben, was beides verbindet?



  • Nur mal so eine Frage: Wofür genau hast du eigentlich zwei koplanare Flächen so nah beieinander?



  • Tomatojuice schrieb:

    Bei Orthogonaler Sicht hab ich ja garkein znear oder zfar.

    Doch klar. Der einzig Unterschied ist, dass dein Sichtvolumen ein Quader ist, und kein Frustum.



  • Tomatojuice schrieb:

    Bei Orthogonaler Sicht hab ich ja garkein znear oder zfar.

    Ausschnitt aus deinem code:

    glOrtho(-m_cameradist*((GLfloat) w/(GLfloat) h)*0.5,    //linke Sichtgrenze
        m_cameradist*((GLfloat) w/(GLfloat) h)*0.5,        //rechte Sichtgrenze
        -m_cameradist*0.5,    //untere Sichtgrenze
        m_cameradist*0.5,    //obere Sichtgrenze
       -40,    //hintere Sichtgrenze  <-- zNear
       40);    //vordere Sichtgrenze  <-- zFar
    }
    

    Hier also zNear = -40 und zFar = 40.

    Bei gluOrtho2D wird zNear per default auf -1 gesetzt und zFar auf 1.



  • dot schrieb:

    Nur mal so eine Frage: Wofür genau hast du eigentlich zwei koplanare Flächen so nah beieinander?

    Also, ich möchte einen Hohlzylinder darstellen, auf dem mehrere kleine Objekte
    drauf sind. Da die Objekte auch sehr klein sind, soll die geringe Wandstärke
    vom Zylinder auch dargestellt werden.

    inter2k3 schrieb:

    -40,    //hintere Sichtgrenze  <-- zNear
       40);    //vordere Sichtgrenze  <-- zFar
    

    Thx!
    hehe, wollt mir schon vor den Kopf schlagen, aber in meinem
    Code wars ja noch nicht drin ^^.



  • Zum Hohlzylinder:

    Du wirst wahrscheinlich einen äusseren Zylidnermantel und einen inneren Zylindermantel zeichnen.
    Du bist schon auf die richtige Idee gekommen, nur hast du sie nicht vollständig umgesetzt. Für die Vertices des inneren Mantels gibst du Normalen an, die in die entgegengesetzte Richtung der Normalen des äusseren Mantels zeigen. Soweit ist das richtig.
    Allerdings differenziert OpenGL nicht anhand der Normalen, ob es sich um eine Vorderseite oder eine Rückseite handelt, sodnern durch die Reihenfolge, in der die Vertices angegeben werden. Die Normalen wären beispielsweise für die Beleuchtung relevant.

    Per default werden Vertices einer Vorderseite (front-face) entgegen des Uhrzeigersinns angegeben (GL_CCW <- counter clock-wise).
    So würdest du die Vertices für den äusseren Mantel angeben. Da es sich beim inneren Mantel um die "Rückseite" handelt, gibst du die Vertices hier im Uhrzeigersinn an.

    Mit glCullFace(GL_BACK) legst du fest, dass die Rückseite nicht gerendert werden soll.
    Dann aktivierst du noch das face-culling mit glEnable(GL_CULL_FACE) und das Problem sollte nicht mehr existieren.


  • Mod

    wenn du genau weisst was du zeichnen willst, und was worauf erscheinen soll, dann kannst du den zbuffer ausschalten und einfach in der gewuenschten reihenfolge zeichnen, dann sollte es auch gehen


Anmelden zum Antworten