Tekstury monochromatyczne 16-bitowe - okienkowanie

0

Witam,

Mam problem związany z OpenGL i nie wiem jak go "ugryźć".
Ładuję teksturę monochromatyczną 16-bitową do maszynki jako teksturę, i wyświetla mi go poprawnie.
Poprawnie - to na razie tyle powiedziane. Docelowo chciałbym, aby maszynka mogła wyświetlić teksturę w następujący sposób:
Zadaję dwa parametry wejściowe (X1 i X2) z zakresu 0-65535 (16 bitów). Maszynka na podstawie tych parametrów wyświetla teksturę w taki sposób, aby wszystkie wartości poniżej X1 były wyświetlane jako czarne, a powyżej X2 - jako białe. Zakres pośredni ma być przeskalowany do głębi bitowej monitora (najczęściej jest to 8 bitów).
W jaki sposób mogę to zrobić?

Poniżej przedstawiam całą procedurę ładowania OpenGL i tekstury:
Tworzenie formy (na samym początku):

procedure TForm1.FormCreate(Sender: TObject);
var
  DC:HDC;
  RC:HGLRC;
begin
  OsX:=0;
  OsY:=0;
  OsZ:=-5;
  Obrot:=0;

  // dla Open GL
  DC:=GetDC(Panel1.Handle);
  SetupPixelFormat(DC);  //wywołanie procedury odpowiedzialnej za ustawienie formatu pikseli
  RC:=wglCreateContext(DC);  //makes OpenGL window out of DC
  wglMakeCurrent(DC, RC);    //makes OpenGL window active
  GLInit; //wywołanie procedury inicjalizującej maszynę stanów OpenGL

end;

Ustawienie formatu pikseli:

procedure TForm1.setupPixelFormat(DC:HDC);
const
   pfd:TPIXELFORMATDESCRIPTOR = (
        nSize:sizeof(TPIXELFORMATDESCRIPTOR); //rozmiar struktury - opisuje rozmiar struktury przekazywanych za pomocą wskaźnika, służy do określenia wielkości pamięci zajmowanej przez strukturę. Umieszczenie w pierwszym polu umożliwia szybkie pobranie przez deferencję wskaźnika.
        nVersion:1; //zawsze wartość 1
        dwFlags:PFD_SUPPORT_OPENGL or PFD_DRAW_TO_WINDOW or PFD_DOUBLEBUFFER; //znaczniki właściwości bufora pikseli - określa właściwości bufora pikseli (PFD_DRAW_TO_WINDOW ? umożliwia tworzenie grafiki w oknie, PFD_SUPPORT_OPENGL ? umożliwia tworzenie grafiki opengl, PFD_DOUBLEBUFFER ? podwójne buforowanie /wyklucza się ze znacznikiem PFD_SUPPORT_GDI/, PFD_SWAP_LAYER_BUFFERS ? urządzenie może przełączać pojedyncze plany warstw z formatami pikseli o podwójnym buforowaniu /w przeciwnym razie wszystkie plany warstw przełączane są grupowo/; jeśli znacznik jest ustawiony, to dostępna jest funkcja wglSwapLayerBuffers, PFD_DEPTH_DONTCARE ? dla danego formatu pikseli może być wykorzystywany bufor głębi, PFD_DOUBLEBUFFER_DONTCARE ? piksele mogą być buforowane pojedynczo lub podwójnie),
        iPixelType:PFD_TYPE_RGBA; //typ danych piksela - określa typ danych piksela (PFD_TYPE_RGBA ? piksele opisane w standardzie RGBA czyli dla każdego piksela określony jest kolor czerwony, zielony, niebieski oraz współczynnik alfa, PFD_TYPE_COLORINDEX ? piksele opisane są za pomocą wartości indeksu koloru),
        cColorBits:24; //liczba bitów piksela - opisuje liczbę bitów określających kolor piksela i może przyjmować wartości 8, 16, 24 i 32. W przypadku gdy karta grafiki nie umożliwia reprezantacji koloru pikseli za pomocą danej liczby bitów to przyjmowana jest jej największa możliwa wartość.
        cRedBits:0; //liczba bitów koloru czerwonego oraz
        cRedShift:0; //przesunięcie bitów koloru czerwonego
        cGreenBits:0; //liczba bitów koloru zielonego
        cGreenShift:0; //przesunięcie bitów koloru zielonego
        cBlueBits:0; //liczba bitów koloru niebieskiego
        cBlueShift:0; //przesunięcie bitów koloru niebieskiego
        cAlphaBits:0; //liczba bitów alfa
        cAlphaShift:0; //przesunięcie bitów alfa
        cAccumBits: 0; //liczba bitów bufora akumulacji
        cAccumRedBits: 0; //liczba bitów akumulacji czerni
        cAccumGreenBits: 0; //liczba bitów akumulacji zieleni
        cAccumBlueBits: 0; //liczba bitów akumulacji błękitu
        cAccumAlphaBits: 0;  //liczba bitów akumulacji alfa
        cDepthBits:16; //liczba bitów bufora głębi
        cStencilBits:0; //liczba bitów bufora powielania
        cAuxBuffers:0; //liczba buforów pomocniczych
        iLayerType:PFD_MAIN_PLANE; //nie jest już wykorzystywany
        bReserved: 0; //liczba podkładanych i nakładanych jednostek
        dwLayerMask: 0; //nie jest już wykorzystywany
        dwVisibleMask: 0; //indeks podłożonej płaszczyzny
        dwDamageMask: 0; //nie jest już wykorzystywany
   );
var
  pixelFormat : integer;
begin
  //ustawienie formatu pikseli
  pixelFormat := ChoosePixelFormat(DC, @pfd);
   if (pixelFormat = 0) then
        exit;
   if (SetPixelFormat(DC, pixelFormat, @pfd) <> TRUE) then
        exit;
end;

Inicjalizacja maszynki:

procedure TForm1.GLInit();
var
  Tablica:PTablica2Word;
  Tab:PTablica1Word;
  Wys,Szer:Cardinal;
  pData:Pointer;
  p:Pointer;
  i,j:Integer;
  Krok:Cardinal;
begin
  glMatrixMode(GL_PROJECTION);
  //glOrtho(0, ClientWidth, 0, ClientHeight, 0, 128);
  glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 25.0);
  glMatrixMode(GL_MODELVIEW);
  glEnable(GL_DEPTH_TEST);

  //ładowanie pliku 3.tiff
  New(Tablica);
  TIFFForm.LoadFile('3.tiff',Tablica,True); //moduł ładujący plik 16-bitowy tiff do tablicy dwuwymiarowej
  TablicaRozmiar(Tablica,Szer,Wys);

  New(Tab);
  SetLength(Tab.Dane,Szer*Wys);
  Krok:=0;
  //wsadzanie danych do bufora
  For i:=0 to Wys-1 do
  Begin
    For j:=0 to Szer-1 do
    Begin
      Tab.Dane[Krok]:=Tablica.Dane[j,i];
      Inc(Krok);
    End;
  End;
  //przypisanie pointera
  pData:=Pointer(@Tab.Dane[0]);
  CreateTexture(Szer,Wys,pData);
  Dispose(Tab);
  Dispose(Tablica);
  //ShowMessage(TimerStop);

  Draw();
end;

Tworzenie tekstury:

function TForm1.CreateTexture(Width,Height:Word;pData:Pointer):Cardinal;
Begin
  glGenTextures(1, Texture);
  glBindTexture(GL_TEXTURE_2D, Texture);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

  //Result:=gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, Width, Height, GL_RGB, GL_UNSIGNED_BYTE, pData); // - gdy ładujemy zwykły RGB 8 bitów na kanał
  //Result:=gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB16, Width, Height, GL_RGB, GL_UNSIGNED_SHORT, pData); // - gdy wsadzamy RGB 16 bitów na kanał
  Result:=gluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE16, Width, Height, GL_LUMINANCE, GL_UNSIGNED_SHORT, pData); // - gdy wsadzamy Mono 16 bitów

  If Result<>0 then
  Begin
    ShowMessage(gluErrorString(Result));
  End;
end;

Rysowanie:

procedure TForm1.Draw();
begin
  Application.ProcessMessages;

  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();

  glTranslatef(OsX,0,0);
  glTranslatef(0,OsY,0);
  glTranslatef(0,0,OsZ);

  glRotate(Obrot,0,1,0);

  glEnable(GL_CULL_FACE);
  glEnable(GL_TEXTURE_2D);

  glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
  glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);


  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);


  glBindTexture(GL_TEXTURE_2D, Texture);

  glBegin(GL_QUADS);
    // Front Face
    glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0,  0.0);
    glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0,  0.0);
    glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0,  0.0);
    glTexCoord2f(0.0, 1.0); glVertex3f(-1.0,  1.0,  0.0);
  glEnd();

  SwapBuffers(wglGetCurrentDC);
end;

Bardzo dziękuję za wszelkie wskazówki.

0

W jaki sposób mogę to zrobić?

być może OpenGL pozwala na taką transformację jakimś shaderem cy cóś... ale aż tak się nie znam. możesz to zrobić „normalnie”:

// pseudokod.
for y:=0 to texture.height-1 do
  for x:=0 to texture.width-1 do
  begin
    if texture.pixels[x,y] < X1 then
        // etc.
  end;
0

Tę metodę mapowania pikseli stosuję obecnie (GDI + Scanline z wykorzystaniem Graphics32), ale to jest zbyt powolna metoda. Samo ładowanie przygotowanych pikseli do maszynki OpenGL trwa dość długo, dlatego zastanawiałem się nad tym, czy można to zrobić już w samej maszynce. Myślałem też o shaderach, nawet o tym, żeby sztucznie oświetlać powierzchnię, ale to nie jest metoda. Shader jest fajny, ale tu jest chyba problem związany z tym, że nie za bardzo mam jak podawać parametry dynamicznie (sam shader przekazuje się do maszynki jako plik...)
Może coś na bazie tworzenia tymczasowych buforów w GPU, jakieś przekształcenia?

0

Jedyna sensowna metoda to zrobienie to po stronie SHADER-a

Shader to funkcja która sie wykonuje dla każdego wierzchołka/piksela
Shader to nie plik tylko zwykła funkcja która mozna uzaleznic od zmiennych w programie.

Kombinowanie po stronie CPU to strata szasu i energii

0

Oczywiście że kombinowanie po stronie CPU to strata czasu.
@Mariusz2, czy masz (znasz) może jakiś dobry wstęp/tutorial do zrobienia takiego shadera w Delphi?

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