Różnice i relacje między glActiveTexture i glBindTexture

Z tego co wiem, glActiveTexture ustawia aktywną "jednostkę tekstury". Każda jednostka tekstury może mieć wiele celów tekstur (Zwykle GL_TEXTURE_1D, 2D, 3D lub CUBE_MAP).

Jeśli dobrze rozumiem, musisz najpierw wywołać glActiveTexture, aby ustawić jednostkę tekstury (inicjalizowaną na GL_TEXTURE0), a następnie powiązać (jeden lub więcej)" cele tekstury " z tą jednostką tekstury?

Liczba dostępnych jednostek tekstur jest zależna od systemu. W mojej bibliotece widzę liczby do 32. To chyba oznacza, że mogę mieć mniejszy limit mojego GPU (który moim zdaniem jest 16 8) i 32 tekstury w pamięci GPU w tym samym czasie? Domyślam się, że jest dodatkowy limit, który nie przekracza maksymalnej pamięci mojego GPU (podobno 1 GB).

Czy dobrze rozumiem związek między celami tekstur a jednostkami tekstur? Powiedzmy, że mogę mieć po 16 jednostek i po 4 cele, czy to oznacza, że jest miejsce na 16 * 4=64 cele, czy to tak nie działa?

Następnie zazwyczaj chcesz załadować Tekstura. Możesz to zrobić poprzez glTexImage2D. Pierwszym argumentem jest Tekstura docelowa. Jeśli to działa jak glBufferData, następnie zasadniczo wiążemy "uchwyt"/" nazwę tekstury " z celem tekstury, a następnie ładujemy dane tekstury do tego celu, a tym samym pośrednio powiązujemy je z tym uchwytem.

A co z glTexParameter? Musimy powiązać cel tekstury, a następnie wybrać ten sam cel ponownie jako pierwszy argument? A może cel tekstury nie musi być związany tak długo, jak mamy skorygować aktywną jednostkę tekstury?

glGenerateMipmap działa też na celu...ten cel musi być nadal związany z nazwą tekstury, aby odnieść sukces?

Następnie, gdy chcemy narysować nasz obiekt z teksturą na nim, czy musimy obie wybrać aktywną jednostkę tekstury, a następnie teksturę docelową? A może wybieramy jednostkę tekstury, a następnie możemy pobrać dane z dowolnego z 4 celów powiązanych z tą jednostką? To jest ta część, która naprawdę mnie myli.

Author: Community, 2012-01-15

4 answers

Wszystko O Obiektach OpenGL

Standardowy model dla obiektów OpenGL jest następujący.

Obiekty mają stan. Pomyśl o nich jak o struct. Możesz więc mieć obiekt zdefiniowany w następujący sposób:

struct Object
{
    int count;
    float opacity;
    char *name;
};

Obiekt ma zapisane pewne wartości i ma Stan. Obiekty OpenGL też mają stan.

Zmiana Stanu

W C / C++, Jeśli masz instancję typu Object, zmienisz jej stan w następujący sposób: obj.count = 5; bezpośrednio odwołujesz się do instancja obiektu, Pobierz konkretny fragment stanu, który chcesz zmienić, i wepchnij do niego wartość.

W OpenGL, nie rób tego.

Aby zmienić stan obiektu OpenGL, musisz najpierw powiązać go z kontekstem. Odbywa się to za pomocą połączenia z glBind*.

Odpowiednik C/C++ jest następujący:

Object *g_objs[MAX_LOCATIONS] = {NULL};    
void BindObject(int loc, Object *obj)
{
  g_objs[loc] = obj;
}

Tekstury są interesujące; stanowią szczególny przypadek wiązania. Wiele wywołań glBind* ma parametr "target". Reprezentuje to różne miejsca w kontekście OpenGL, w których obiekty tego typu mogą być powiązane. Na przykład można powiązać obiekt bufora ramki do odczytu (GL_READ_FRAMEBUFFER) lub zapisu (GL_DRAW_FRAMEBUFFER). Wpływa to na sposób, w jaki OpenGL używa bufora. To właśnie reprezentuje powyższy parametr loc.

Tekstury są specjalne, ponieważ kiedypo raz pierwszy połączysz je z celem, otrzymają one specjalne informacje. Kiedy po raz pierwszy związujesz teksturę jako GL_TEXTURE_2D, w rzeczywistości ustawia specjalny stan w teksturze. Mówisz, że ta tekstura jest teksturą 2D. I będzie zawsze teksturą 2D; tego stanu nie można zmienić nigdy . Jeśli masz teksturę, która została najpierw związana jako GL_TEXTURE_2D, musisz zawsze związać ją jako GL_TEXTURE_2D; próba związania jako GL_TEXTURE_1D spowoduje błąd (podczas wykonywania).

Gdy obiekt jest związany, jego stan może zostać zmieniony. Odbywa się to za pomocą funkcji ogólnych specyficznych dla tego obiekt. Oni też zajmują miejsce, które reprezentuje, który obiekt zmodyfikować.

W C/C++ wygląda to tak:

void ObjectParameteri(int loc, ObjectParameters eParam, int value)
{
  if(g_objs[loc] == NULL)
    return;

  switch(eParam)
  {
    case OBJECT_COUNT:
      g_objs[loc]->count = value;
      break;
    case OBJECT_OPACITY:
      g_objs[loc]->opacity = (float)value;
      break;
    default:
      //INVALID_ENUM error
      break;
  }
}

Zauważ, jak ta funkcja ustawia to, co dzieje się w aktualnie przypisanej wartości loc.

Dla obiektów tekstur głównymi funkcjami zmieniającymi stan tekstur są glTexParameter. Jedynymi innymi funkcjami, które zmieniają stan tekstury są glTexImage funkcje i ich odmiany (glCompressedTexImage, glCopyTexImage, Ostatnie glTexStorage). Różne wersje SubImage zmieniają zawartość tekstury, ale technicznie nie zmieniają jej stanu . Funkcje Image przydzielają magazyn tekstur i ustawiają format tekstury; funkcje {[23] } po prostu kopiują piksele wokół. To nie jest uważane za stan tekstury.

Powtórzę: są to tylko funkcje, które modyfikują stan tekstury. glTexEnv modyfikuje stan środowiska; nie wpływa na nic przechowywanego w teksturze obiektów.

Active Texture

Sytuacja w przypadku tekstur jest bardziej złożona, ponownie ze względów starszych, najlepiej pozostawić ją nieujawnioną. Tutaj glActiveTexture wchodzi.

W przypadku tekstur nie są tylko cele (GL_TEXTURE_1D, GL_TEXTURE_CUBE_MAP, itp.). Istnieją również jednostki tekstury . W naszym przykładzie C/C++ mamy to:

Object *g_objs[MAX_OBJECTS][MAX_LOCATIONS] = {NULL};
int g_currObject = 0;

void BindObject(int loc, Object *obj)
{
  g_objs[g_currObject][loc] = obj;
}

void ActiveObject(int currObject)
{
  g_currObject = currObject;
}

Zauważ, że teraz mamy nie tylko dwuwymiarową listę Object s, ale także koncepcję bieżącego obiektu. Mamy funkcja aby ustawić bieżący obiekt, mamy koncepcję maksymalnej liczby bieżących obiektów, a wszystkie nasze funkcje manipulacji obiektami są dostosowane do wyboru z bieżącego obiektu.

Kiedy zmieniasz aktualnie aktywny obiekt, zmieniasz cały zestaw lokalizacji docelowych. Możesz więc powiązać coś, co przechodzi do bieżącego obiektu 0, przełączyć się na bieżący obiekt 4 i będzie modyfikować zupełnie inny obiekt.

Ta analogia z obiektami tekstur jest doskonała... prawie.

Zobacz, glActiveTexture nie przyjmuje liczby całkowitej, lecz przyjmujewyliczenie . Co w teorii oznacza, że może przyjmować wszystko od GL_TEXTURE0 do GL_TEXTURE31. Ale jest jedna rzecz, którą musisz zrozumieć: {]}

TO NIEPRAWDA!

Rzeczywisty zakres, który glActiveTexture może przyjąć, jest regulowany przez GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS. Jest to maksymalna liczba jednoczesnych multitextur, na jaką pozwala implementacja. Każdy z nich jest podzielony na różne grupy dla różnych etapów shadera. Na przykład na GL 3.sprzęt klasy X, otrzymujesz 16 tekstur cieniowania wierzchołków, 16 tekstur cieniowania fragmentów i 16 tekstur cieniowania geometrii. Zatem {[35] } będzie 48.

Ale nie ma 48 wyliczeń. Dlatego glActiveTexture tak naprawdę nie wymaga enumeratorów. poprawny sposób wywołania glActiveTexture jest następujący:

glActiveTexture(GL_TEXTURE0 + i);

Gdzie i jest liczbą od 0 do GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.

Rendering

Więc co to wszystko ma wspólnego z renderowaniem?

Kiedy używając shaderów, ustawiasz uniformy samplera na jednostkę obrazu tekstury (glUniform1i(samplerLoc, i), gdzie i jest jednostką obrazu). Oznacza to liczbę, której użyłeś z glActiveTexture. Sampler wybierze cel na podstawie typu samplera. Więc {[44] } wybierze z GL_TEXTURE_2D celu. Jest to jeden z powodów, dla których samplery mają różne typy.

Teraz brzmi to podejrzanie, jakbyś mógł mieć dwa samplery GLSL, z różnymi typami , które używają tej samej jednostki obrazu tekstury. Ale nie możesz; OpenGL zabrania tego i spowoduje błąd podczas próby renderowania.

 217
Author: Nicol Bolas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-07 13:44:10

Spróbuję ! Wszystko to nie jest takie skomplikowane, tylko kwestia terminów, mam nadzieję, że się wyjaśnię.


Możesz utworzyć mniej więcej tyle obiektów tekstur , ile jest dostępnej pamięci w Twoim systemie. Obiekty te przechowują rzeczywiste dane (tekstury) Twoich tekstur wraz z parametrami dostarczonymi przez glTexParameter (zobacz FAQ).

Podczas tworzenia, musisz przypisać jeden obiekt Tekstury do jednego obiektu tekstury, który reprezentuje typ tekstury (GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE, ...).

Te dwa elementy, texture object i texture target reprezentują dane tekstury. Wrócimy do nich później.

Jednostki Tekstury

Teraz OpenGL dostarcza tablicę jednostek tekstury , które mogą być używane jednocześnie podczas rysowania. Wielkość tablicy zależy od systemu OpenGL, Twój ma 8.

Możesz powiązać obiekt tekstury z Jednostka tekstury używająca danej tekstury podczas rysowania.

W prostym i łatwym świecie, aby narysować daną teksturę, powiązałbyś obiekt tekstury z jednostką tekstury i wykonałbyś (pseudocode):

glTextureUnit[0] = textureObject
Ponieważ GL jest maszyną stanową, niestety tak nie działa. Przypuśćmy, że nasza textureObject mA dane dla celu GL_TEXTURE_2D tekstury, wyrazimy poprzednie przypisanie jako:
glActiveTexture(GL_TEXTURE0);                   // select slot 0 of the texture units array
glBindTexture(GL_TEXTURE_2D, textureObject);    // do the binding

Zauważ, że GL_TEXTURE_2D naprawdę zależy od rodzaju tekstury, którą chcesz bind.

Obiekty Tekstury

W pseudo kodzie, aby ustawić dane tekstury lub parametry tekstury, wykonaj na przykład :

setTexData(textureObject, ...)
setTexParameter(textureObject, TEXTURE_MIN_FILTER, LINEAR)

OpenGL nie może bezpośrednio manipulować obiektami tekstur, aby zaktualizować/ustawić ich zawartość lub zmienić ich parametry, musisz najpierw powiązać je z aktywną jednostką tekstur (niezależnie od tego, która z nich jest). Odpowiednikiem kodu jest :

glBindTexture(GL_TEXTURE_2D, textureObject)       // this 'installs' textureObject in texture unit
glTexImage2D(GL_TEXTURE_2D, ...)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

Shadery

Shadery mają dostęp do wszystkich jednostek tekstur, nie dbają o aktywna Tekstura.

Uniformy próbnika są wartościami int reprezentującymi indeks jednostki tekstury używanej dla próbnika (a Nie obiektu tekstury używanego).

Więc musisz powiązać Obiekty Tekstury z jednostkami, których chcesz użyć.

Typ próbnika dopasuje się do celu tekstury, który jest używany w jednostce tekstury : Sampler2D dla GL_TEXTURE_2D, i tak dalej...

 15
Author: rotoglup,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-23 04:38:30

Wyobraź sobie GPU jak jakiś Zakład Obróbki farb.

Istnieje wiele zbiorników, które dostarczają barwnik do jakiejś Maszyny do malowania. W maszynie malarskiej barwnik jest następnie nakładany na obiekt. Te czołgi to jednostki tekstury

Zbiorniki te mogą być wyposażone w różne rodzaje barwników. Każdy rodzaj barwnika wymaga innego rodzaju rozpuszczalnika. "Rozpuszczalnik "to cel tekstury . Dla wygody każdy zbiornik jest podłączony do pewnego źródła rozpuszczalnika, ale tylko jeden rodzaj rozpuszczalnika może być używany na raz w każdym zbiorniku. Więc jest zawór / przełącznik TEXTURE_CUBE_MAP, TEXTURE_3D, TEXTURE_2D, TEXTURE_1D. Można wypełnić wszystkie rodzaje barwników w zbiorniku w tym samym czasie, ale ponieważ tylko jeden rodzaj rozpuszczalnika idzie w, będzie "rozcieńczyć" tylko rodzaj dopasowania barwnika. Możesz więc wiązać każdy rodzaj tekstury, ale wiązanie z" najważniejszym " rozpuszczalnikiem faktycznie trafi do zbiornika i wymieszuje się z rodzajem barwnika, do którego należy.

I jest jeszcze sam barwnik, który pochodzi z magazyn i jest napełniany do zbiornika przez "związanie" go. To twoja Tekstura.

 12
Author: datenwolf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-23 04:38:51

Jeśli w Twoim shaderze potrzebujesz przeszukiwania z 2 tekstur:

uniform sampler2D tex1;  
uniform sampler2D tex2;  

Należy wskazać dla tex1 i tex2 ich źródła w następujący sposób:

tex1 = gl.createTexture();  
gl.activeTexture(gl.TEXTURE3);  
gl.bindTexture(gl.TEXTURE_2D, tex1); 
gl.texParameteri(gl.TEXTURE_2D, ...);  
....


tex2 = gl.createTexture();  
gl.activeTexture(gl.TEXTURE7);  
gl.bindTexture(gl.TEXTURE_2D, tex2); 
gl.texParameteri(gl.TEXTURE_2D, ...);  
....  
var tex1Loc  = gl.getUniformLocation(your_shader,"tex1");  
var tex2Loc  = gl.getUniformLocation(your_shader,"tex2");

W pętli renderowania:

gl.uniform1i(tex1Loc, 3);  
gl.uniform1i(tex2Loc, 7);  
// but you can dynamically change these values

Z gl_bindtexture nie da się tego zrobić. Z drugiej strony możliwe użycie bind w pętli renderowania, jest w przypadku, gdy karmisz teksturę z zawartością w strumieniu (wideo, kamera internetowa): {]}

gl.bindTexture(gl.TEXTURE_2D, tex1);  
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video);  
// in the render loop
 1
Author: Philippe Oceangermanique,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-20 19:49:58