Problem z wykorzystaniem całego okna i współrzędnymi w OpenGL

0

Jako że zaczynam przygotowywać projekt w Delphi na studia (przy znajomości Pascala, po raz pierwszy mając przed oczami OpenGL), postanowiłem skorzystać z możliwości wykorzystania OpenGL do wyświetlania elementów gry (bo projekt ten ma być właśnie grą - 2D).

Udało mi się przygotować środowisko to pracy w takim duecie (Delphi7 + OpenGL), jednak mam pewne problemy:

  1. Wykorzystywanie całego formularza Delphi.
    W ramach testów przygotowanego środowiska, próbowałem tworzyć sobie różne figury przy użyciu OpenGL i za którymś razem chciałem spróbować wypełnić całe okno, by zrobić coś w rodzaju tła. Wpisałem dość duże współrzędne wierzchołków tworzonej figury i oto co ukazało się moim oczom:
    http://img13.imageshack.us/img13/1144/przechwytywaniegg.png
    To raczej nie problem złego ustawienia Viewportu, myślę, że raczej odpowiadają za to wartości ClientWidth i ClientHeight formularza Delphi. Podczas gdy okno ma 800x600 pikseli, wartości tych właściwości wynoszą odpowiednio 784 i 562 piksele. Nie dam rady zwiększyć tych wartości ani też ich zmniejszyć - są chyba ustawione na sztywno dla danego rozmiaru okna. Wygląda to trochę, jakby Delphi zostawiał miejsce dla scrollbarów, ale ja chciałbym, by tego nie robił (w każdym razie chciałbym uniknąć tych brzydkich czarnych marginesów).
    Ustawiłem sobie w Delphi stałe rozmiary formularza, w którym będzie odbywać się cała gra - 800x600 (edytując parametry Max/MinWidth i Max/MinHeight), ale nie wiem, czy to mogło mieć wpływ na powstanie problemu.

  2. Współrzędne w OpenGL.
    Przygotowałem sobie środowisko tak, że "początek" układu współrzędnych OpenGL znajduje się na środku formularza, do którego odbywa się rendering - jak jednak przewidzieć, jakie mniej więcej współrzędne znajdują się w innych miejscach formularza, np. w 3/4 długości, na skrajnym prawym czy też dolnym brzegu? Myślałem, że będą one ustawiane zgodnie z rozmiarem formularza, ale tak nie jest - z moich testów wynika, że dla OpenGL współrzędna dolnego brzegu okna to ~100 a prawego brzegu ~140. Oczywiście jestem w stanie sobie zasymulować własny układ współrzędnych, który będzie dla mnie wygodny, ale muszę przynajmniej znać jakiś stosunek między współrzędnymi OpenGL i tymi, które chce wprowadzić (a obecnie kompletnie nie wiem dlaczego OpenGL wybrał sobie akurat takie współrzędne w poszczególnych miejscach).

Z góry dzięki za wszelkie (p)odpowiedzi,
Michał.

0
kremuwa napisał(a)

bo projekt ten ma być właśnie grą - 2D

Znowu...

kremuwa napisał(a)

Wpisałem dość duże współrzędne wierzchołków tworzonej figury

Przecież znasz zarówno rozmiar formularza jak i roboczy rozmiar okna (ClientWidth & ClientHeight) to po co kombinujesz? Ustawiając Width formularza na 800 zauważyć przecież można, że rozmiar klienta zmniejsza się dokładnie o szerokość ramki okna * 2, a nie żadne miejsce na ScrollBar;

kremuwa napisał(a)

Nie dam rady zwiększyć tych wartości ani też ich zmniejszyć - są chyba ustawione na sztywno dla danego rozmiaru okna. [...] Ustawiłem sobie w Delphi stałe rozmiary formularza, w którym będzie odbywać się cała gra - 800x600 (edytując parametry Max/MinWidth i Max/MinHeight), ale nie wiem, czy to mogło mieć wpływ na powstanie problemu.

Bzdura, trzeba było się nie bawić z MinHeight, MaxHeight, MinWidth, MaxWidth to mógłbyś modyfikować rezmiary okna;

kremuwa napisał(a)

jak jednak przewidzieć, jakie mniej więcej współrzędne znajdują się w innych miejscach formularza, np. w 3/4 długości, na skrajnym prawym czy też dolnym brzegu?

No bez jaj, przecież takie rzeczy się w podstawówce oblicza... Żeby takie coś policzyć wystarczy znać szerokość klienta i podstawowe działania jak dodawanie, odejmowanie, mnożenie i dzielenie...

kremuwa napisał(a)

a obecnie kompletnie nie wiem dlaczego OpenGL wybrał sobie akurat takie współrzędne w poszczególnych miejscach

OpenGL nie mógł sobie "wybrać" współrzędnych...

0

Zamiast użyć bardzo porządnego DelphiX, to nie.. lepiej się paprać z OpenGL'em...

0
TomRiddle napisał(a)

Zamiast użyć bardzo porządnego DelphiX, to nie.. lepiej się paprać z OpenGL'em...

Ty to potrafisz zmotywować człowieka...

Poniżej masz objaśnienie czterech właściwości, które musisz znać (oraz w nawiasach zakres pikseli według Twojego planu):

FormProps.png

Sam oceń i zastanów się w jaki sposób obliczyć współrzędne;

EDIT: Szerokość ramek można obliczyć tak (dla WinXP, styl Luna):

{ BOCZNE RAMKI I DOLNA }
iSideBorderWidth := (Width - ClientWidth) div 2;
{ GÓRNA RAMKA }
iTopBorderHeight := Height - ClientHeight - iSideBorderWidth;
0

@Furious Programming - chyba Cię trochę poniosło. Prawdopodobnie pomyliłem się co do źródła mojego problemu i przez to nie do końca zrozumiałeś jego istotę, nie ma powodu do wściekania się (no, może tylko o fakt, że gra 2d pojawia się tu po raz milion n-ty, ale cóż - taki mam projekt do zrobienia i mam z nim problem).

Ustawiając Width formularza na 800 zauważyć przecież można, że rozmiar klienta zmniejsza się dokładnie o szerokość ramki okna * 2, a nie żadne miejsce na ScrollBar;

I zauważyłem to jeszcze przed utworzeniem tematu, że zmienia się o stałą liczbę (nie wiedziałem tylko, że to właśnie przestrzeń na ramki) - problem w tym, że sądziłem, że różnica między Width a ClientWidth (i analogicznie Height i ClientHeight) jest źródłem czarnych marginesów, widocznych na screenie z pierwszego posta. Po Twoim poście rozumiem, że różnica między nimi to miejsce na ramkę okna. Pytanie zatem, co w takim razie powoduje pojawienie się tych marginesów z pierwszego screena?

Bzdura, trzeba było się nie bawić z MinHeight, MaxHeight, MinWidth, MaxWidth to mógłbyś modyfikować rezmiary okna

Nie zrozumiałeś. Nie chodziło o to, że nie mogę zmieniać rozmiaru okna po uruchomieniu aplikacji, tylko o to, że przy zadanym Width i Height właściwości ClientWidth i ClientHeight są ustalone, nie do zmiany (i tak, teraz rozumiem dlaczego). A ustawić sobie stałe rozmiary okna mam przecież prawo.

No bez jaj, przecież takie rzeczy się w podstawówce oblicza... Żeby takie coś policzyć wystarczy znać szerokość klienta i podstawowe działania jak dodawanie, odejmowanie, mnożenie i dzielenie...

Podaj mi w takim razie przykład, jak obliczyć, jakie współrzędne OpenGL znajdują się np. w prawym dolnym rogu Clienta o rozmiarach 800x600 (rozumiem, że to obszar wewnątrz ramek okna, tak?).

Pozdrawiam.

0
kremuwa napisał(a)

chyba Cię trochę poniosło.

Tak, przykro mi;

kremuwa napisał(a)

Prawdopodobnie pomyliłem się co do źródła mojego problemu i przez to nie do końca zrozumiałeś jego istotę

Odpisałem Ci na temat jaki napisałeś; Skąd mogłem wiedzieć, że nie o to Ci chodziło..? Skoro tego nie napisałeś to nie miałem prawa wiedzieć :P

kremuwa napisał(a)

Nie chodziło o to, że nie mogę zmieniać rozmiaru okna po uruchomieniu aplikacji, tylko o to, że przy zadanym Width i Height właściwości ClientWidth i ClientHeight są ustalone, nie do zmiany

??? Nie bardzo rozumiem co to znaczy; W każdym razie jeżeli masz mieć cały czas taki sam rozmiar okna, to właściwości takie jak Width, Height, ClientWidth i ClientHeight będą stałe; Z resztą nie ma nawet o czym pisać, zawsze będą stałe bo rozmiar samej ramki się nie zmieni (chyba, że user zmieni styl obramowania okien w systemie, ale i tak ostatnie dwie właściwości pozostaną bez zmian); Pokręcone to ale prawdziwe;

kremuwa napisał(a)

A ustawić sobie stałe rozmiary okna mam przecież prawo.

No pewnie, nikt Ci przecież nie broni;

kremuwa napisał(a)

rozumiem, że to obszar wewnątrz ramek okna, tak?

To jest właśnie obszar roboczy formularza; Na ramkach też można malować itd., ale funkcjami WinAPI (co najmniej na pasku tytułowym formularza);

kremuwa napisał(a)

Podaj mi w takim razie przykład, jak obliczyć, jakie współrzędne OpenGL znajdują się np. w prawym dolnym rogu Clienta o rozmiarach 800x600

Już tłumaczę; Otóż jeżeli biorąc pod uwagę fakt, iż rozmiar roboczy formularza ma rozmiary 800 x 600 px, współrzędne mają następujące wartości:

  • lewy górny róg - [0, 0]
  • prawy górny róg - [799, 0]
  • lewy dolny róg - [0, 599]
  • prawy dolny róg - [799, 599]
    Zawsze będą to takie wartości, nie inaczej (chyba, że Delphi 7 kłamie);

Jeżeli Twój program robi taką dziwną ramkę, sprawdź taki kod u siebie:

procedure TForm1.FormClick(Sender: TObject);
begin
  with Form1.Canvas do
    begin
      Pixels[0, 0] := clFuchsia;
      Pixels[799, 599] := clFuchsia;
    end;
end;

Czy Twój program narysował różowe kropki w lewym górnym i prawym dolnym rogu w obszarze roboczym formularza czy gdzie indziej? Bo jeżeli gdzie indziej, to z jakiegoś powodu; Ja mam WinXP i D7 i u mnie zawsze rysuje w ww rogach; Może OpenGL chce narysować tło nie w obszarze roboczym formularza (klienta) tylko od lewego górnego rogu okna? Dlatego wychodzi u Ciebie czarna ramka;

Nie mam u siebie OpenGL, więc nie przetestuję, ale podaj kod, którym malujesz tło, bo z fusów Ci nic nie wywróżę;

0

No widzisz, właśnie w tym cały problem (oprócz tych dziwnych marginesów), że współrzędne w OpenGL (argumenty, które podaje funkcjom OpenGL tworzącym figury) nie bardzo "chcą" być tymi samymi współrzędnymi Delphi, o których piszesz, zmieniającymi się wraz z przesuwaniem się w prawo i w dół od lewego górnego rogu aż do szerokości/wysokości obszaru roboczego - i o tym pisałem w pierwszym poście. Pracowałem już z kilkoma bibliotekami w C++ (Allegro, SFML), z frameworkiem Qt do aplikacji okienkowych i naprawdę wiem, jak to zazwyczaj działa :).

Oto moja procedura renderująca (tworząca figurę, który zajmuje więcej niż cały viewport (czyli także więcej niż obszar roboczy):

procedure TForm1.Render;
begin
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  glPushMatrix();
  gluLookAt(0.0, 0.0, 150.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

  glBegin (GL_QUADS);
  glColor3f(1.0, 1.0, 1.0); glVertex3f( -155, 155, 1 );
  glColor3f(0, 0.6, 1.0); glVertex3f( -155, -140, 1 );
  glColor3f(0, 0.6, 1.0); glVertex3f( 155, -140, 1 );
  glColor3f(1.0, 1.0, 1.0); glVertex3f( 155, 155, 1 );
  glEnd;

  glPopMatrix();
  glFlush();
  SwapBuffers(wglGetCurrentDC);
end;

Uwierz lub nie, ale wystarczą takie współrzędne wierzchołków, jakie podałem funkcjom glVertex(), by rozciągnąć figurę na cały Viewport (tak, jak to widać na pierwszym screenie), a tak naprawdę nawet poza jego granice. I właśnie o te współrzędne pytałem od pierwszego postu - dlaczego nie są tożsame ze współrzędnymi Delphi, podanymi przez Ciebie - chodzi mi głównie o skalę, bo początek układu współrzędnych znajduje się dokładnie na środku obszaru, do którego rysuję (czyli inaczej Viewportu, znajdującego się - chyba - wewnątrz obszaru roboczego) - bo tak jest w grafice 3D.
Wiem, że w OpenGL mamy jeszcze trzecią współrzędną, będącą tu "odległością od ekranu", ale w swoim programie stosuję funkcję glOrtho(), która podobno anuluje perspektywę.

Dodałem sobie Twój kod do programu i rysuje on różowe pixele dokładnie w lewym górnym i prawym dolnym rogu ekranu (oczywiście po wyłączeniu funkcji rysujących oraz glClear() czyszczącej mi... hmm... okno na kolor czarny), więc raczej wszystko z tej strony jest ok.

Do przygotowania sobie środowiska OpenGL użyłem gotowej instrukcji. Obecnie tworząc OpenGL'owy Viewport wywołuję go z szerokością ClientWidth i ClentHeight:

width := GLsizei(control.ClientWidth); 
height:= GLsizei(control.ClientHeight);
glViewport( -10, 10, width, height );

GLsizei to konwersja na liczbę całkowitą, na wszelki wypadek (była w instrukcji).
Spróbowałem na siłę zwiększyć ostatnie dwa argumenty przesyłane do funkcji, dodając do nich +50, by sprawdzić, czy to problem Viewportu - na szerokość to podziałało, na wysokość niestety nie. Teraz mam więc czarny pasek tylko w dolnej części okna.

Mam nadzieję, że przy okazji nie przemyciłem żadnej głupoty, jak tamta z miejscem na scrollbary.

0
kremuwa napisał(a)

że współrzędne w OpenGL (argumenty, które podaje funkcjom OpenGL tworzącym figury) nie bardzo "chcą" być tymi samymi współrzędnymi Delphi

Właśnie przez takie rzeczy nie mogę rzucić palenia... Niby wszystko gra, a jednak gdzieś jest bubel... denerwujące no ale...

Nie wiem już naprawdę jak Ci pomóc, gdzieś przecież musi być jakiś bubel; Mam jedno pytanie: co oznacza -10 i 10 w trzeciej linii tego kodu:

Width := GLSizeI(Control.ClientWidth); 
Height := GLSizeI(Control.ClientHeight);
GLViewport(-10, 10, Width, Height );

i jakiego typu jest podany w kodzie Control? Dlaczego stosując stały rozmiar formularza nie przyjmujesz stałych wartości? Próbowałeś inaczej? Na sztywno wpisać rozmiar klienta?

GLViewport(-10, 10, 800, 600);
kremuwa napisał(a)

GLSizeI to konwersja na liczbę całkowitą, na wszelki wypadek

Przecież rozmiar okna zawsze jest liczbą całkowitą; Nie wiem czemu konwertujesz tą liczbę;

EDIT: Wygooglowałem przykładowe użycie procedury GLViewport i dowiedziałem się, że pierwsze dwa parametry oznaczają XOffset i YOffset; Napisz co się stanie jak wywołasz tę procedurę tak:

GLViewport(0, 0, 800, 600);
kremuwa napisał(a)

Mam nadzieję, że przy okazji nie przemyciłem żadnej głupoty, jak tamta z miejscem na scrollbary.

Nie mam o to do Ciebie żalu :P

0

Tak to jest, jak się korzysta z gotowych instrukcji z błędami... po wyzerowaniu tych wartości Offsetu viewport jest już oczywiście ustalony jak należy - "marginesy" zniknęły. Dzięki :). Mam sobie za złe, że nie sprawdziłem prototypu tej funkcji.

Odpowiadając na Twoje pytanie - rozmiary okna (argumenty funkcji glViewport) nie były wpisane na sztywno, bo kod był kopiowany z instrukcji, która była przygotowana pod ogólny przypadek - czyli np. okno o zmiennym rozmiarze. Podobnie z GLSizeI() - sam jej tam nie wstawiłem, też się zdziwiłem jej obecnością, kod był przeklejany.

Pozostaje pytanie o współrzędne w OpenGL - jak się one "układają" przy używaniu projekcji Ortographic, czyli przy porzuceniu perspektywy. Coraz bardziej przychylnie patrzę na poleconą mi w komentarzu bibliotekę Andorra 2D. Pewien troskliwy student poradził nam skorzystać z OpenGL (czyli biblioteki 3D) w wersji trochę upośledzonej (o perspektywę) do zrobienia gry 2D, przygotował do tego nawet poradnik. Wydaje mi się, że to jednak kiepski pomysł, nie licząc faktu, że pewnie działałoby to relatywnie szybko. Chciałbym sobie np. łatwo wyświetlać bitmapy, do czego Andorra będzie, jak sądzę, znacznie lepsza.

Tak czy siak, dzięki za pomoc - jeśli ktoś tutaj zna OpenGL i wie jak można sobie przygotować wygodny układ współrzędnych do gry 2D (by nie trzeba było metodą prób i błędów sprawdzać, gdzie jest jaka współrzędna), wątek stoi otworem, z chęcią posiądę tę wiedzę.

0
kremuwa napisał(a)

po wyzerowaniu tych wartości Offsetu viewport jest już oczywiście ustalony jak należy - "marginesy" zniknęły.

No to się cieszę; To mi się właśnie najbardziej rzucało w oczy, ale nie znałem znaczenia pierwszych dwóch parametrów, stąd nie chciałem mieszać;

kremuwa napisał(a)

Odpowiadając na Twoje pytanie - rozmiary okna (argumenty funkcji glViewport) nie były wpisane na sztywno, bo kod był kopiowany z instrukcji, która była przygotowana pod ogólny przypadek - czyli np. okno o zmiennym rozmiarze. Podobnie z GLSizeI() - sam jej tam nie wstawiłem, też się zdziwiłem jej obecnością, kod był przeklejany.

Ctrl+C i Ctrl+V to nie jest najlepsze rozwiązanie; Nie wolno takich rzeczy robić, bo później wychodzą właśnie takie problemy; Nie ma kodu uniwersalnego, zawsze zdaży się przypadek, gdzie potrzeba kod modyfikować, więc lepiej czytać kod i dostosowywać go dla własnych potrzeb;

kremuwa napisał(a)

Pozostaje pytanie o współrzędne w OpenGL - jak się one "układają" przy używaniu projekcji Ortographic, czyli przy porzuceniu perspektywy.

Bez testowania się nie obejdzie; Jeżeli w dokumentacji procedur z OpenGL nic na ten temat nie jest napisane, musisz przeprowadzić kilka testów, w których sprawdzisz współrzędne; Chyba, że istnieje jakaś procedura, którą ustala się początek układu współrzędnych, wtedy łatwo będzie go ustawić w wygodne dla Ciebie miejsce i stosownie do niego obliczać pozycje nowych obiektów; Ale nie jestem niczego pewny, bo tak jak wspominałem nie pracowałem nigdy z tym silnikiem;

kremuwa napisał(a)

wie jak można sobie przygotować wygodny układ współrzędnych do gry 2D

Zależy gdzie on ma się znaleźć; Wszystko da się prosto obliczyć; Jeżeli układ z OpenGL ma początek na środku formularza:

CntrCrd.png

a Ty chcesz mieć w lewym górnym rogu:

CrnrCrd.png

musisz napisać sobie funkcję tłumaczącą współrzędne z OpenGL na Twoje:

function TranslatePoint(const pntOGL: TPoint): TPoint;
begin
  Result.X := pntOGL.X + 400;
  Result.Y := Abs(pntOGL.Y - 300);
end;

Wszystko jednak zależy od tego gdzie Ty chcesz aby był początek układu i od tego gdzie on jest według OpenGL;

(rysunki, końcowa treść postu oraz kod funkcji tłumaczącej zostały nieznacznie zmienione ze względu na posiadanie błedów w pierwszej wersji)

1 użytkowników online, w tym zalogowanych: 0, gości: 1