Jawne a automatyczne powiązanie lokalizacji atrybutów dla modułów cieniujących OpenGL

83

Podczas konfigurowania lokalizacji atrybutów dla programu cieniującego OpenGL masz do wyboru dwie opcje:

glBindAttribLocation () przed połączeniem, aby jawnie zdefiniować lokalizację atrybutu.

lub

glGetAttribLocation () po połączeniu w celu uzyskania automatycznie przypisanej lokalizacji atrybutu.

Jakie jest narzędzie do używania jednego nad drugim?

A który z nich jest preferowany w praktyce?

Jing
źródło
6
Nie zawracałem sobie głowy używaniem glBindAttribLocationw moim silniku graficznym, który ładnie działał na Linuksie. Kiedy przeportowałem do systemu Windows, używał moich normalnych jako wierzchołków - musiałem wyraźnie powiedzieć mu kolejność zmiennych w moim module cieniującym przez glBindAttribLocation, aby działał ...
Jarrett

Odpowiedzi:

93

Znam jeden dobry powód, by preferować jednoznaczną definicję lokalizacji.

Weź pod uwagę, że przechowujesz dane geometryczne w Vertex Array Objects. Dla danego obiektu tworzysz VAO w taki sposób, aby indeksy odpowiadały np .:

  • indeks 0 : pozycje,
  • indeks 1 : normalne,
  • indeks 2 : texcoords

Teraz zastanów się, czy chcesz narysować jeden obiekt za pomocą dwóch różnych shaderów . Jeden moduł cieniujący wymaga danych dotyczących pozycji i normalnych jako danych wejściowych, a drugi - pozycji i współrzędnych tekstur .

Jeśli skompilujesz te moduły cieniujące, zauważysz, że pierwszy moduł cieniujący będzie oczekiwał pozycji o indeksie atrybutu 0, a normalnych o wartości 1. Drugi będzie oczekiwał pozycji na 0, ale współrzędnych tekstur na 1.

Cytując https://www.opengl.org/wiki/Vertex_Shader :

Automatyczne przypisywanie

Jeśli żadna z dwóch poprzednich metod nie przypisuje wejścia do indeksu atrybutu, indeks jest automatycznie przypisywany przez OpenGL, gdy program jest połączony. Przypisany indeks jest całkowicie dowolny i może być inny dla różnych programów, które są połączone, nawet jeśli używają dokładnie tego samego kodu Vertex Shader.

Oznacza to, że nie byłbyś w stanie używać swojego VAO z obydwoma shaderami. Zamiast jednego VAO na, powiedzmy, obiekt, potrzebujesz - w najgorszym przypadku - oddzielnego VAO na obiekt na moduł cieniujący .

Zmuszenie shaderów do używania własnej konwencji numerowania atrybutów poprzez glBindAttribLocationmoże łatwo rozwiązać ten problem - wszystko, co musisz zrobić, to zachować spójną relację między atrybutami a ich ustalonymi identyfikatorami i zmusić shadery do korzystania z tej konwencji podczas łączenia.

(To nie jest duży problem, jeśli nie używasz oddzielnych VAO, ale mimo to może sprawić, że kod będzie bardziej przejrzysty).


BTW:

Podczas konfigurowania lokalizacji atrybutów dla programu cieniującego OpenGL masz do wyboru dwie opcje

W OpenGL / GLSL 3.3 jest trzecia opcja: Określ lokalizację bezpośrednio w kodzie modułu cieniującego . To wygląda tak:

layout(location=0) in vec4 position;

Ale to nie jest obecne w języku shaderów GLSL ES.

Kos
źródło
1
Nie widzę sensu. VAO są naprawdę lekkie i zwykle będziesz je odtwarzać dla każdej ramy. W twoim przypadku po prostu utworzyłbyś różne VAO przed wywołaniem każdego shadera, prawda?
PierreBdR
1
Tak, oczywiście możesz to zrobić. Będzie działać równie dobrze, omawiamy tutaj tylko konwencje. :)
Kos
4
Trzecia opcja jest faktycznie dostępna w GLES2.0, ale format jest nieco inny: układ (lokalizacja = 0) atrybut pozycja vec4; Zauważ, że będziesz również potrzebować tego na górze pliku GLSL: #extension GL_EXT_separate_shader_objects: enable
Gavin Maclean
35
„VAO są naprawdę lekkie i zazwyczaj odtwarzasz je dla każdej klatki. W twoim przypadku po prostu utworzyłbyś różne VAO przed wywołaniem każdego shadera, prawda?” - Nie, zwykle tego nie zrobisz, ponieważ ostatecznie unieważnia to cały cel VAO. Po co więc w ogóle używać VAO?
Christian Rau
2
Tylko uwaga. Nie przechowywałbyś danych geometrii w VAO. To byłoby w VBO. VAO nie mają przechowywania danych.
średnio joe
20

Inną odpowiedzią jest to, że glGetAttribLocation zwraca dane do obiektu wywołującego, co oznacza, że ​​niejawnie wymaga opróżnienia potoku. Jeśli wywołasz to zaraz po skompilowaniu programu, zasadniczo wymuszasz synchroniczną kompilację asynchroniczną.

Litherum
źródło
Dzięki, to bardzo ważna uwaga.
Jing
1
Rozumiem, że w większości sytuacji i tak musiałbyś zadzwonić glGetUniformLocation; czy ta szczególna uwaga jest nadal aktualna?
Mike Weir
@MikeWeir od wersji GL 4.3 możesz ustawić jednoznaczną jednolitą lokalizację .
Ruslan,
1
@Ruslan Używają OpenGL ES.
Mike Weir
9

Trzecia opcja, czyli layout(location=0) in vec4 position;w kodzie shadera, jest teraz dostępna w OpenGL ES 3.0 / GLSL 300 es. Jednak tylko dla zmiennych wejściowych Vertex Shader.

pas ruchu
źródło
7
Jak sugerują, karty Intela mogą tego nie obsługiwać (chociaż są doskonale kompatybilne z 3.0+ inaczej, jak to rozumiem), co jest obrzydliwe :)
mlvljr