Udostępnij za pośrednictwem


Wskazówki: brak obiektów spowodowany cieniowaniem wierzchołków

W tym instruktażu przedstawiono sposób użycia narzędzi programu Visual Studio Graphics Diagnostics do zbadania obiektu brakującego z powodu błędu, który wystąpił podczas etapu cieniowania wierzchołków.

Ten instruktaż ilustruje następujące zadania:

  • Używanie Listy zdarzeń grafiki do lokalizowania potencjalnych źródeł problemu.

  • Używanie okna Etapy potoku grafiki do sprawdzania efektu wywołań interfejsu Direct3D API DrawIndexed.

  • Używanie debugera języka HLSL do zbadania modułu cieniującego wierzchołków.

  • Używanie Stosu wywołań zdarzeń grafiki do znajdowania źródła niepoprawnej stałej HLSL.

Scenariusz

Jedna z częstych przyczyn braku obiektu w aplikacji 3-D występuje wtedy, gdy program do cieniowania wierzchołków przekształca wierzchołki obiektu w sposób nieoczekiwany lub niepoprawny — obiekt może być na przykład skalowany do bardzo małego rozmiaru lub przekształcony tak, że wydaje się umieszczony za kamerą, a nie przed nią.

W tym scenariuszu po uruchomieniu aplikacji, aby ją przetestować, tło jest renderowane zgodnie z oczekiwaniami, ale nie ma jednego z obiektów.Przy użyciu programu Graphics Diagnostics można przechwytywać problemy do dziennika grafiki, dzięki czemu można debugować aplikację.Problem w aplikacji wygląda następująco:

Obiekt nie są widoczne.

Dochodzenie

Za pomocą narzędzi programu Graphics Diagnostics można załadować plik dziennika grafiki, aby skontrolować klatki, które zostały przechwycone podczas testu.

Aby sprawdzić ramkę w dzienniku grafiki

  1. W programie Visual Studio załaduj dziennik grafiki zawierający ramkę, która wykazuje brak obiektu.Nowa karta Dziennik grafiki pojawia się w programie Visual Studio.W górnej części tej karty jest obiekt docelowy renderowania zaznaczonej klatki.W dolnej części jest sekcja Lista klatek, która wyświetla każdą przechwyconą klatkę jako obraz miniatury.

  2. W oknie Lista klatek zaznacz klatkę, która pokazuje, że obiekt nie jest wyświetlany.Obiekt docelowy renderowania został zaktualizowany, aby odzwierciedlić wybraną ramkę.W tym scenariuszu karta dziennika grafiki wygląda następująco:

    Grafika dokumentu dziennika w programie Visual Studio

Po zaznaczeniu klatki, która demonstruje problem, można rozpocząć jego diagnozowanie za pomocą okna Lista zdarzeń grafiki.Lista zdarzeń graficznych zawiera wszystkie wywołania API Direct3D, które zostały wykonane w celu renderowania aktywnej ramki, np. wywołania interfejsu API w celu konfiguracji stanu urządzenia, utworzenia i aktualizacji buforów oraz narysowania obiektów pojawiających się w ramce.Wiele rodzajów wywołań jest interesujących, ponieważ często (ale nie zawsze) jest odnośna zmiana obiekcie docelowym renderowania, gdy aplikacja działa zgodnie z oczekiwaniami, na przykład przy wywołaniach rysowania, wysyłki, kopiowania lub czyszczenia.Wywołania rysowania są szczególnie interesujące, ponieważ każde z nich reprezentuje geometrię wyrenderowaną przez aplikację (wywołania wysyłki również mogą renderować geometrię).

Ponieważ wiadomo, że brakujący obiekt jest nie rysowany do obiektu docelowego renderowania (w tym przypadku), jednak pozostała część sceny jest rysowana zgodnie z oczekiwaniami, można użyć okna Lista zdarzeń grafiki wraz z narzędziem Etapy potoku grafiki, aby sprawdzić, które wywołanie rysowania odpowiada brakującej geometrii obiektu.W oknie Etapy potoku grafiki jest przedstawiona geometria wysyłana do każdego wywołania rysunku, bez względu na jej wpływ na renderowany obiekt docelowy.Gdy przechodzisz przez kolejne wywołania rysowania, etapy potoku są aktualizowane, aby wyświetlić geometrię skojarzoną z wywołaniem, a docelowy obiekt renderowania jest aktualizowany w celu pokazania jego stanu po wywołaniu.

Aby znaleźć wywołanie rysowania dla braku geometrii

  1. Otwórz okno Lista zdarzeń grafiki.Na pasku narzędzi programu Graphics Diagnostics wybierz przycisk Lista zdarzeń.

  2. Otwórz okno Etapy potoku grafiki.Na pasku narzędzi programu Graphics Diagnostics wybierz przycisk Etapy potoku.

  3. Przechodząc przez kolejne wywołania rysowania w oknie Lista zdarzeń grafiki, w oknie Etapy potoku grafiki szukaj brakującego obiektu.Aby to ułatwić, wprowadź "Draw" w polu Wyszukaj w prawym górnym rogu okna Lista zdarzeń grafiki.Filtruje listę, tak aby zawiera tylko zdarzenia, które mają "Draw" w tytule.

    W oknie Etapy potoku grafiki etap Asembler danych wejściowych pokazuje geometrię obiektu przed jego przekształceniem, a etap Cieniowanie wierzchołków pokazuje ten sam obiekt po przekształceniu.W tym scenariuszu wiesz, że został znaleziony brakujący obiekt, gdy jest wyświetlany na etapie Asembler danych wejściowych, a nic nie jest wyświetlane na etapie Cieniowanie wierzchołków.

    [!UWAGA]

    Jeśli inne etapy geometrii — na przykład moduł cieniowanie powłoki, cieniowanie domeny lub cieniowanie geometrii — przetwarzają obiekt, mogą być przyczyną problemu.Zazwyczaj problem dotyczy najwcześniejszego etapu, w którym wynik nie jest wyświetlany lub jest wyświetlany w nieoczekiwany sposób.

  4. Zatrzymaj po osiągnięciu wywołania rysowania odpowiadającego brakującemu obiektowi.W tym scenariuszu okno Etapy potoku grafiki wskazuje, że geometria została wysłana do procesora GPU (wskazanego przez miniaturę asemblera danych wejściowych), ale nie pojawia się w obiekcie docelowym renderowania, ponieważ coś poszło źle na etapie cieniowania wierzchołków (wskazywanym przez miniaturę programu do cieniowania wierzchołków):

    Zdarzenie DrawIndexed i jego wpływu na potoku

Po potwierdzeniu, że aplikacja wysłała wywołanie rysowania brakującej geometrii obiektu i odkryciu, że problem dzieje się podczas etapu cieniowania wierzchołków, można użyć debugera języka HLSL do zbadania cieniowania wierzchołków i ustalenia, co się stało z geometrią obiektu.HLSL Debugger może być użyty do sprawdzenia stanu zmiennych HLSL podczas wykonywania, przejścia przez kod HLSL i ustalenia punktów przerwania w celu zdiagnozowania problemu.

Aby sprawdzić cieniowanie wierzchołków

  1. Rozpocznij debugowanie etapu modułu cieniującego wierzchołka.W oknie Etapy potoku grafiki w etapie Cieniowanie wierzchołków wybierz przycisk Rozpocznij debugowanie.

  2. Ponieważ etap Asembler danych wejściowych najwyraźniej dostarcza dobrych danych dla cieniowania wierzchołków, a etap Cieniowanie wierzchołków najwyraźniej nie generuje żadnych obiektów wyjściowych, należy zbadać strukturę wyjściową cieniowania wierzchołków — output.Przechodząc przez kolejne fragmenty kodu języka HLSL, przyjrzyj się bliżej, kiedy jest modyfikowana sekcja output.

  3. Przy pierwszej modyfikacji output następuje zapis do worldPos członka.

    Wartość "output.worldPos" pojawia się stosowne

    Ponieważ wartość jego wydaje się być uzasadniona, kontynuuj przechodzenie przez kod krok po kroku aż do następnego wiersza, który modyfikuje sekcję output.

  4. Przy kolejnej modyfikacji output następuje zapis pos składowej.

    Wyzerowanie wartości "output.pos"

    Tym razem wartość członka pos — same zera — jest podejrzana.Następnie chcesz ustalić, jak plik output.pos otrzymał same wartości zerowe.

  5. Zauważ, że output.pos przyjmuje wartość zmiennej o nazwie temp.W poprzednim wierszu widać, że wartość elementu temp jest wynikiem pomnożenia poprzedniej wartości przez stałą o nazwie projection.Podejrzewasz, że niestandardowa wartość elementu temp jest wynikiem tego mnożenia.Po umieszczeniu wskaźnika na projection można zauważyć, że jego wartość to również same zera.

    Projekcja macierzy zawiera uszkodzone transformacji

    W tym scenariuszu badanie wykazało, że podejrzana wartość elementu temp jest najprawdopodobniej spowodowana jej pomnożeniem przez wartość projection, ponieważ projection jest stałą, która ma zawierać macierz rzutowania, wiadomo, że nie powinna zawierać samych zer.

Po ustaleniu, że stała języka HLSL projection — przekazywana do programu do cieniowania przez Twoją aplikację — jest prawdopodobne źródło problemu, następnym krokiem jest znalezienie lokalizacji w kodzie źródłowym aplikacji, gdzie jest wypełniany bufor stałych.Można użyć Stosu wywołań zdarzeń grafiki, aby znaleźć tę lokalizację.

Aby dowiedzieć się, gdzie stała jest ustawiona w kodzie źródłowym aplikacji

  1. Otwórz okno Stos wywołań zdarzeń grafiki.Na pasku narzędzi programu Graphics Diagnostics wybierz przycisk Stos wywołań zdarzeń grafiki.

  2. Przechodź w górę stosu wywołań do kodu źródłowego aplikacji.W oknie Stos wywołań zdarzeń grafiki wybierz wywołanie na samej górze, aby zobaczyć, czy bufor stałych jest tam wypełniany.Jeśli nie, przechodź dalej w górę stosu wywołań, aż znajdziesz, gdzie jest wypełniany.W tym scenariuszu odkrywasz, że bufor stałych jest wypełniany — za pomocą interfejsu API UpdateSubresource programu Direct3D — wyżej w stosie wywołań, w funkcji o nazwie MarbleMaze::Render, oraz że jego wartość pochodzi z obiektu buforu stałych o nazwie m_marbleConstantBufferData:

    Kod, który ustawia bufor stała obiektu

    PoradaPorada

    Jeśli jednocześnie debugujesz swoją aplikację, możesz ustawić punkt przerwania w tej lokalizacji. Zostanie on osiągnięty podczas renderowania następnej klatki.Następnie można sprawdzić członków m_marbleConstantBufferData, aby potwierdzić, że jako wartość elementu członkowskiego projection ustawiono same zera po wprowadzeniu stałej buforu.

Po znalezieniu lokalizacji, gdzie jest wypełniany bufor stałych, i odkryciu, że jego wartości pochodzą ze zmiennej m_marbleConstantBufferData, następnym krokiem jest dowiedzenie się, gdzie członek m_marbleConstantBufferData.projection jest ustawiany na same zera.Można użyć polecenia Znajdź wszystkie odwołania, aby wykonać szybkie skanowanie w poszukiwaniu kodu, który zmienia wartość m_marbleConstantBufferData.projection.

Aby dowiedzieć się, gdzie element członkowski rzutu jest ustawiony w kodzie źródłowym aplikacji

  1. Znajdź odwołania do elementu m_marbleConstantBufferData.projection.Otwórz menu skrótów dla zmiennej m_marbleConstantBufferData, a następnie wybierz polecenie Znajdź wszystkie odwołania.

  2. Aby przejść do lokalizacji wiersza w kodzie źródłowym aplikacji, gdzie członek projection jest zmodyfikowany, wybierz ten wiersz w oknie wyników wyszukiwania symbolu.Ponieważ pierwszy wynik, który modyfikuje element członkowski rzutu, może nie być przyczyną problemu, należy zbadać kilka obszarach kodu źródłowego aplikacji.

Po znalezieniu lokalizacji, gdzie jest ustawiany element m_marbleConstantBufferData.projection, możesz sprawdzić otaczający kod źródłowy w celu ustalenia pochodzenia niepoprawnej wartości.W tym scenariuszu odkryjesz, że jako wartość elementu m_marbleConstantBufferData.projection jest ustawiana zmienna lokalna o nazwie projection, zanim jest on inicjowany z wartością podaną przez kod m_camera->GetProjection(&projection); w następnym wierszu.

Projekcja marble ustawiono przed inicjowania

Aby rozwiązać ten problem, przenieś wiersz kodu, który ustawia wartość m_marbleConstantBufferData.projection po wierszu, który inicjuje wartość zmiennej lokalnej projection.

Skorygowany kodu źródłowego języka C++

Po naprawieniu kodu możesz go zrekompilować i uruchomić aplikację ponownie, aby odkryć, że problem z renderowaniem został rozwiązany:

Obiekt w teraz wyświetlane.