Mapowanie atrybutów Vertex shader w GLSL

Koduję mały silnik renderujący z shaderami GLSL:

Każda Siatka (well, submesh) ma pewną liczbę strumieni wierzchołkowych (np. position, normal, texture, tangent, etc)w jednym dużym VBO i MaterialID.

Każdy materiał ma zestaw tekstur i właściwości (np. specular-color, diffuse-color, color-texture,normal-map, etc)

Potem mam GLSL shader, z mundurami i atrybutami. Powiedzmy:

uniform vec3 DiffuseColor;
uniform sampler2D NormalMapTexture;
attribute vec3 Position;
attribute vec2 TexCoord;

Trochę utknąłem próbując zaprojektować sposób na GLSL shader definiuje mapowania strumieni (semantyki) dla atrybutów i uniformów, a następnie wiąże strumienie wierzchołków z odpowiednimi atrybutami.

Coś w linijkach powiedzenia do siatki : "umieść swój Strumień Pozycji w atrybucie "Position" i twoje współrzędne tex w "TexCoord". Możesz również umieścić rozproszony kolor materiału w "DiffuseColor", a drugą teksturę materiału w "NormalMapTexture" [7]}

W tej chwili używam ciężko zakodowanych nazw dla atrybutów (tj. vertex pos jest zawsze "Position", itp.) i sprawdzanie każdego uniformu i nazwy atrybutów, aby zrozumieć, do czego shader go używa.

Myślę, że szukam jakiegoś sposobu na stworzenie "deklaracji wierzchołków", ale w tym również mundurów i tekstur.

Zastanawiam się, jak ludzie robią to w silnikach renderujących na dużą skalę.

Edit:

Podsumowanie sugerowanych metod:

1. Atrybut / Uniform semantic jest podany przez nazwę zmiennej (co robię teraz) Używanie predefiniowanych nazw dla każdego możliwego atrybutu.Segregator GLSL zapyta o nazwę każdego atrybutu i połączy tablicę wierzchołków na podstawie nazwy zmiennej:

//global static variable

semantics (name,normalize,offset) = {"Position",false,0} {"Normal",true,1},{"TextureUV,false,2}

 ...when linking
for (int index=0;index<allAttribs;index++)
{
   glGetActiveAttrib(program,index,bufSize,length,size[index],type[index],name);      
   semantics[index]= GetSemanticsFromGlobalHardCodedList(name);
} 
... when binding vertex arrays for render
 for (int index=0;index<allAttribs;index++)
{
    glVertexAttribPointer(index,size[index],type[index],semantics[index]->normalized,bufferStride,semantics[index]->offset);

}  

2. Predefiniowane lokalizacje dla każdego semantycznego

Binder GLSL będzie zawsze wiązał tablice wierzchołków do tego samego locations.It jest do shadera, aby użyć odpowiednich nazw, aby dopasować. (Wydaje się to strasznie podobne do metody 1, ale chyba źle zrozumiałam, oznacza to powiązanie wszystkich dostępnych dane wierzchołków, nawet jeśli shader ich nie zużywa)

.. when linking the program...
glBindAttribLocation(prog, 0, "mg_Position");
glBindAttribLocation(prog, 1, "mg_Color");
glBindAttribLocation(prog, 2, "mg_Normal");

3. Słownik dostępnych atrybutów z materiału, Globali silnika, renderera i siatki

Utrzymuj listę dostępnych atrybutów opublikowanych przez aktywny materiał, Globale silnika, bieżący Renderer i bieżący węzeł sceny.

Eg:

 Material has (uniformName,value) =  {"ambientColor", (1.0,1.0,1.0)}, {"diffuseColor",(0.2,0.2,0.2)}
 Mesh has (attributeName,offset) = {"Position",0,},{"Normals",1},{"BumpBlendUV",2}

Następnie w shader:

 uniform vec3 ambientColor,diffuseColo;
 attribute vec3 Position;

Podczas wiązania danych wierzchołków z shaderem, spoiwo GLSL zapętli się nad atrybutami i połączy się z jednym znalezione (czy nie? ) w słowniku:

 for (int index=0;index<allAttribs;index++)
    {
       glGetActiveAttrib(program,index,bufSize,length,size[index],type[index],name);      
      semantics[index] = Mesh->GetAttributeSemantics(name);
}

I to samo z uniformami, pytaj tylko o aktywny materiał i globale.

Author: Radu094, 2011-02-02

3 answers

Atrybuty:

Twoja siatka ma wiele strumieni danych. Dla każdego strumienia możesz zachować następujące informacje: (nazwa, typ, DANE).

Po połączeniu, możesz odpytywać program GLSL o aktywne atrybuty i utworzyć słownik atrybutów dla tego programu. Każdy element tutaj jest po prostu (nazwa, typ ).

Gdy rysujesz siatkę za pomocą określonego programu GLSL, przechodzisz przez słownik atrybutów programów i wiążesz odpowiednie strumienie siatki (lub zgłaszanie błędu w przypadku niespójności).

Mundury:

Niech słownik parametru shader będzie zbiorem (nazwa, typ, łącze danych). Zazwyczaj można mieć następujące słowniki:

    [[23]} Materiał (rozproszony,specular,lśniący, itp.) - pobrany z materiału W 2007 roku firma została założona przez Marka S. A., a w 2008 roku została założona przez firmę S. A.]}
  • Render (własne parametry związane z twórcą shadera: SSAO radius, blur w przeciwieństwie do innych formatów, nie można ich używać.]}

Po połączeniu, program GLSL otrzymuje zestaw słowników parametrów w celu wypełnienia własnego słownika następującym formatem elementów: (location, type, data link ). Ta populacja jest wykonywana przez sprawdzenie listy aktywnych uniformów i dopasowanie (nazwa, typ ) do pary w słownikach.

Wniosek: Ta metoda pozwala na dowolne niestandardowe atrybuty wierzchołków i umundurowanie shader ' a, bez zakodowanych na twardo nazw/semantyki w silniku. W zasadzie tylko loader i render wiedzą o konkretnej semantyce:

  • Loader wypełnia deklaracje strumieni danych mesh i słowniki materiałów.
  • Render używa shadera, który zna nazwy, dostarcza dodatkowych parametrów i wybiera odpowiednie siatki do rysowania.
 14
Author: kvark,
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
2011-02-07 21:58:18

Z mojego doświadczenia wynika, że OpenGL nie definiuje pojęcia atrybutów ani semantyki uniformów.

Wszystko, co możesz zrobić, to zdefiniować swój własny sposób mapowania Twojej semantyki do zmiennych OpenGL, używając tylko parametru, który możesz kontrolować o tych zmiennych: ich Lokalizacja.

Jeśli nie jesteś ograniczony przez problemy z platformą, możesz spróbować użyć "nowego" GL_ARB_explicit_attrib_location (rdzeń w OpenGL 3.3, jeśli się nie mylę), który pozwala shaderom na jawnie wyrazić, która lokalizacja jest przeznaczona dla którego atrybutu. W ten sposób możesz kodować na twardo (lub konfigurować) dane, które chcesz powiązać z lokalizacją atrybutów, i odpytywać lokalizacje shaderów po ich skompilowaniu. Wydaje się, że ta funkcja nie jest jeszcze dojrzała i być może podlega błędom w różnych sterownikach.

Odwrotnie jest, aby powiązać lokalizacje atrybutów za pomocą glBindAttribLocation . W tym celu musisz znać nazwy atrybutów, które chcesz do wiązania i lokalizacje, które chcesz przypisać.

Aby poznać nazwy używane w shaderze, Możesz:

  • zapytanie shadera o aktywne atrybuty
  • przeanalizuj kod źródłowy shadera, aby znaleźć je samodzielnie]}

Nie zalecałbym używania sposobu parsowania GLSL (chociaż może on odpowiadać Twoim potrzebom, jeśli znajdujesz się w wystarczająco prostym kontekście): parser może być łatwo pokonany przez preprocesor. Przypuśćmy, że Twój kod shadera staje się nieco skomplikowany, możesz chcieć aby zacząć używać # includes, # defines, # ifdef, itd. Solidne parsowanie zakłada, że masz solidny preprocesor, który może stać się dość ciężkim podnoszeniem do skonfigurowania.

W każdym razie, z aktywnymi nazwami atrybutów, musisz przypisać im lokalizacje (i / lub semantykę), w tym celu jesteś sam ze swoim przypadkiem użycia.

W naszym silniku z radością kodujemy na twardo lokalizacje predefiniowanych nazw do określonych wartości, takich jak:

glBindAttribLocation(prog, 0, "mg_Position");
glBindAttribLocation(prog, 1, "mg_Color");
glBindAttribLocation(prog, 2, "mg_Normal");
...

Po tym, to do Shader writer dostosować się do predefiniowana semantyka atrybutów.

AFAIK jest to najczęstszy sposób robienia rzeczy, OGRE używa go na przykład. To nie jest rocket science, ale działa dobrze w praktyce.

Jeśli chcesz dodać jakąś kontrolę, możesz dostarczyć API do definiowania semantyki na podstawie shadera, być może nawet mając ten opis w dodatkowym pliku, łatwo przetwarzalnym, mieszkającym w pobliżu kodu źródłowego shadera.

Nie wchodzę w mundury, gdzie sytuacja jest prawie taka sama, z wyjątkiem że "nowsze" rozszerzenia pozwalają wymusić jednolite bloki GLSL do układu pamięci zgodnego z Twoją aplikacją.

Sama nie jestem zadowolona z tego wszystkiego, więc chętnie będę miała jakieś sprzeczne informacje:)

 8
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
2013-05-31 03:22:02

Możesz rozważyć parsowanie samego GLSL.

Składnia deklaracji uniform/atrybut jest dość prosta. Możesz wymyślić mały ręczny parser, który szuka linii zaczynających się od uniform lub attribute, pobrać typ i nazwę, a następnie wystawić niektóre API C++ za pomocą łańcuchów. Zaoszczędzi ci to kłopotu z ciężko zakodowanymi nazwami. Jeśli nie chcesz pobrudzić sobie rąk ręcznym parsowaniem, kilka rodzajów Spirit załatwi sprawę.
Prawdopodobnie nie będziesz chciał aby w pełni przeanalizować GLSL, musisz upewnić się, że nie robisz nic śmiesznego w opóźnieniach, które mogą zmienić rzeczywiste znaczenie. Jedną z komplikacji, która przychodzi na myśl, jest kompilacja warunkowa przy użyciu makr w GLSL.

 3
Author: shoosh,
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
2011-02-07 09:05:11