Autor Wątek: OpenGL: Bufor głębi nie działa prawidłowo  (Przeczytany 1488 razy)

Offline chudzielec

  • Użytkownik

# Luty 25, 2009, 11:23:18
Witam,

Mam dosyć poważny problem z buforem głębi w OpenGL. Problem objawia się tym, że wygląda tak, jakby jego wartości były ustawione nieprawidłowo, ale nie dzieje się to losowo. Oto screeny:

http://atom.bounceme.net/~chudy/cube/

(jeśli llink przestanie działać, parę postów niżej jest zip: http://forum.warsztat.gd/index.php?action=dlattach;topic=9965.0;attach=1473)

Wszystkie oprócz nr. 4 i 5 były rysowane w kolejności najpierw linie, potem sześcian. Gdy jest odwrotnie efekt jest podobny, ale minimalnie gorszy. Zauważyłem, że efekt się nie zmienia gdy nie oddalam się od widzialnych wierzchołków, a zmienia tylko kiedy zmienię rotację bądź przybliżenie.

Technologicznie używam jogl i dotąd działało wszystko bezproblemowo.

Inicjalizacja:
Kod: (java) [Zaznacz]
private void init(GLAutoDrawable drawable) {
       
        final GL gl = drawable.getGL();
       
        gl.glShadeModel(GL.GL_SMOOTH);

        gl.glEnable(GL.GL_BLEND);

        gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);

        gl.glClearColor(255/255f, 255/255f, 191/255f, 0.0f);

        gl.glClearDepth(1.0f);

        gl.glEnable(GL.GL_DEPTH_TEST);

        gl.glDepthFunc(GL.GL_LEQUAL);

        gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
       
        // światło
        gl.glEnable(GL.GL_CULL_FACE);
        gl.glFrontFace(GL.GL_CCW);
       
        FloatBuffer ambientLight = FloatBuffer.wrap(new float[] { 0.3f, 0.5f, 0.8f, 1.0f });
        FloatBuffer diffuseLight = FloatBuffer.wrap(new float[] { 0.8f, 0.8f, 0.8f, 1.0f });
        FloatBuffer lightPosition = FloatBuffer.wrap(new float[] { 100.0f, 100.0f, +100.0f, 0.0f });
       
        gl.glEnable(GL.GL_LIGHTING);
       
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, ambientLight);
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuseLight);
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPosition);
       
        gl.glEnable(GL.GL_LIGHT0);
    }

Zmiana rozmiaru okna:

Kod: (java) [Zaznacz]
private void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
       
        final GL gl = drawable.getGL();

        if (height <= 0) {
                height = 1;
        }

        final float h = (float) width / (float) height;

        gl.glMatrixMode(GL.GL_PROJECTION);

        gl.glLoadIdentity();

        glu.gluPerspective(50.0f, h, 0.0, 1000.0);

        gl.glMatrixMode(GL.GL_MODELVIEW);

        gl.glLoadIdentity();
    }
   

Rysowanie:

Kod: (java) [Zaznacz]
    private void display(GLAutoDrawable drawable) {
       
        final GL gl = drawable.getGL();
       
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        gl.glLoadIdentity();
       
        gl.glMatrixMode(GL.GL_MODELVIEW);
       
        // obracam kamerę
        gl.glRotated(cameraRotation.x, 1.0, 0.0, 0.0);
        gl.glRotated(cameraRotation.y, 0.0, 1.0, 0.0);
        gl.glRotated(cameraRotation.z, 0.0, 0.0, 1.0);
       
        // przesuwam względem ustalonej pozycji kamery
        gl.glTranslated(-cameraPosition.x, -cameraPosition.y, -cameraPosition.z);
     
       
        DrawContext drawContext = new StandardDrawContext(gl);
       
        // inicjalizuje warstwy, które jeszcze nie zostały zainicjalizowane
        model.initializeLayers(drawContext);
       
        // rysuję wszystkie warstwy
        for(Layer l : model.getLayers()) {
            l.draw(drawContext);
        }
       
        gl.glFlush();
       
    }

To co się dzieje podczas rysowania modeli Model#draw() to proste glBegin(GL_LINES) czy glBegin(GL_QUADS), parę glVertex3f() i poprawnie kończone przez glEnd()
« Ostatnia zmiana: Luty 25, 2009, 13:52:59 wysłana przez chudzielec »

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline .:NOXY:.

  • Użytkownik
    • Profil

# Luty 25, 2009, 11:52:44
spróbuj włączać stan gl.Enable(GL.GL_DEPTH_TEST);  przed narysowaniem obiektu a wyłączać po i zobacz co sie stanie
no i ładuj rysowanie w stos poprzez glPushMatrix() glPopMatrix()

Offline chudzielec

  • Użytkownik

# Luty 25, 2009, 12:06:38
Byłeś blisko, nie sprawdziłem tego w taki sposób. Efekt niestety niezmienny.

Offline Avaj

  • Użytkownik

# Luty 25, 2009, 12:21:19
używając blendingu   
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
trzeba renderować w odpowiedniej kolejności obiekty, w twoim przypadku wyglądałoby to tak:

z-test włączony, z-write włączony, blending wyłączony
renderujesz linie
wyłączasz z-write (glDepthMask(GL_FALSE) ), włączasz blending
renderujesz sześcian, sortując ściany od najdalszej do najbliższej

Offline chudzielec

  • Użytkownik

# Luty 25, 2009, 12:42:51
Nie zależy mi w tym przykładzie na blendingu tak naprawdę. Mogłem to usunąć od razu. glDisable(GL_BLEND) nie przynosi widocznych rezultatów.

Offline Krzysiek K.

  • Moderator
    • DevKK.net

# Luty 25, 2009, 13:20:09
Cytuj
glu.gluPerspective(50.0f, h, 0.0, 1000.0);
Kto przy zdrowych zmysłach ustawia near clipping plane na zero? Zrobienie czegoś takiego albo w praktyce wyłacza z-bufor (redukuje dokładność do zera). :)

Offline Avaj

  • Użytkownik

# Luty 25, 2009, 13:28:06
Cytuj
glu.gluPerspective(50.0f, h, 0.0, 1000.0);
Kto przy zdrowych zmysłach ustawia near clipping plane na zero? Zrobienie czegoś takiego albo w praktyce wyłacza z-bufor (redukuje dokładność do zera). :)
o kurcze, nie zauważyłem tego :P

tak, to może być klucz do wszystkiego

Offline chudzielec

  • Użytkownik

# Luty 25, 2009, 13:51:32
Problem rozwiązany! Dziękuję bardzo, całuję w nóżki ;-)


Dodałem zip z plikami, które umieściłem w pierwszym poście dla osób, które będą miały z tym samym problem w przyszłości.

Btw. Czemu tak się dzieje?

Offline Krzysiek K.

  • Moderator
    • DevKK.net

# Luty 25, 2009, 14:30:02
Cytuj
Btw. Czemu tak się dzieje?
Wartości w z-buforze nie są przechowywane jako zwykłe Z, tylko jako pewien fragment zakresu funkcji 1/Z, bo tak wymuszają macierze, poza tym dzięki temu rozdzielczość z-bufora spada wraz z odległością i jest lepiej wykorzystywana (bliższe obiekty mają większą precyzję Z niż dalsze). Ustawiając near i far clipping plane wybieramy, który fragment funkcji 1/Z mapujemy na bity z-bufora. Far clipping plane możemy ustawić bardzo daleko bez znacznej straty precyzji, ponieważ jak bardzo by Z nie rosło, to 1/Z nie spadnie poniżej zera (fakt faktem, można zakres mapowania poniżej zera, dzięki czemu obiekty nie będą w stanie osiągnąć far clipping plane i będziemy mieć nieskończony zakres widoku). Z near clipping plane nie jest już tak wesoło, bo im mniejsze Z dopuszczamy, tym wartości funkcji 1/Z stają się szybko coraz większe. Jeżeli far clipping plane jest dostatecznie daleko, przybliżenie near clipping plane o połowę powoduje spadek precyzji z-bufora reszty sceny też o połowę. Ustawiając near clipping plane na zero musielibyśmy pozwolić na nieskończone wartości funkcji 1/Z (1/0 = Inf), a więc z mapowaniem funkcji 1/Z dzieją się nieciekawe rzeczy. :)

Offline chudzielec

  • Użytkownik

# Luty 25, 2009, 14:32:30
Zrozumiałe, dzięki :-)