Compartilhar via


Instruções passo a passo: objetos ausentes devido ao sombreamento de vértice

Essa explicação passo a passo demonstra como usar as ferramentas Graphics Diagnostics de Visual Studio para investigar um objeto que está faltando devido a um erro que ocorre durante a fase do sombreador de vértice.

Essa explicação passo a passo ilustra essas tarefas:

  • Usando a Lista de Eventos de Elementos Gráficos para localizar fontes potenciais do problema.

  • Usando a janela Fases do Pipeline de Elementos Gráficos para verificar o efeito de chamadas DrawIndexed Direct3D API.

  • Usando o Depurador HLSL para examinar o sombreador do vértice.

  • Uso s Pilha de chamadas de Eventos de Elementos Gráficos para ajudar a localizar a origem de uma constante incorreta de HLSL.

Cenário

Às vezes, os objetos não aparecem em aplicativos 3D. Geralmente isso ocorre quando o sombreador de vértice transforma os vértices do objeto de maneira incorreta ou inesperada. Por exemplo, o objeto pode ser dimensionado para um tamanho muito pequeno ou transformado de modo que apareça atrás da câmera, e não na frente dela.

Neste cenário, quando o aplicativo é executado para testá-lo, o plano de fundo é renderizado como esperado, mas um dos objetos não aparece. Usando o Diagnósticos Gráficos, você captura o problema para o registro de gráficos de modo a depurar o aplicativo. O problema tem esta aparência no aplicativo:

O objeto não pode ser visto.

Investigação

Usando as ferramentas de Diagnósticos Gráficos, você pode carregar o arquivo de log gráficos para inspecionar os quadros capturados durante o teste.

Para examinar um quadro no registro de elementos gráficos

  1. Em Visual Studio, carregar um log dos gráficos que contém um quadro que exibe o objeto ausente. Uma nova guia de log de gráficos aparece no Visual Studio. Na parte superior desta guia está a saída de destino da renderização do quadro selecionado. Na parte inferior está a Lista do Quadro, que exibe cada quadro capturado como a imagem miniatura.

  2. Na Lista do Quadro, selecionar um quadro que demonstra que o objeto não é exibido. O destino de processamento é atualizado para refletir o quadro selecionado. Neste cenário, a guia do log dos gráficos parecem como esta:

    O documento de log de gráficos no Visual Studio

Depois de selecionar um quadro que demonstra este problema, é possível começar a diagnosticá-lo usando a Lista de eventos de gráficos. A Lista de eventos gráficos contém todas as chamadas à API de Direct3D feitas para renderizar o quadro ativo, por exemplo, chamadas à API para configurar o estado do dispositivo, para criar e atualizar buffers e para desenhar objetos que aparecem no quadro. Muitos tipos de chamadas são interessantes porque há geralmente (mas não sempre) uma mudança correspondente no destino processar quando o aplicativo está funcionando como esperado, por exemplo, chamadas por Desenho, Despacho, Cópia ou Limpeza. As chamadas de desenho são particularmente interessantes porque cada uma representa uma geometria que o aplicativo renderiza (chamadas de distribuição também podem renderizar a geometria.)

Como você sabe que o objeto ausente não está sendo desenhado ao destino de renderização (neste caso) — mas que o resto da cena é desenhada como esperado - é possível usar Lista de eventos de gráficos juntamente com a ferramenta Fases da canalização de gráficos para determinar qual chamada de desenho corresponde à geometria do objeto ausente. A janela Etapas do pipeline gráfico mostra a geometria enviada para cada chamada de desenho, independentemente do efeito no destino renderização. Conforme você move pelas chamadas de desenho, as fases de canalização são atualizados para mostrar a geometria associada com aquele chamada e a saída de destino de renderização é atualizada para mostrar o estado de destino de renderização após a chamada ser concluída.

Para localizar a chamada de desenho para a geometria ausente

  1. Abra a janela Lista de Eventos de Gráficos. Na barra de ferramentas Diagnóstico de Gráficos, escolha Lista de Eventos.

  2. Abra a janela Estágios de Pipeline Gráficos. Na barra de ferramentas Diagnóstico de Gráficos, escolha Estágios de Pipeline.

  3. Conforme você move por cada chamada na janela Lista de eventos de gráficos, veja a janela Fases do pipeline de gráficos para o objeto ausente. Para tornar isso mais fácil, digite um “Desenho” na caixa Pesquisar no canto superior direito da janela Lista de eventos de elementos gráficos . Isso filtra a lista de modo que ela contenha somente os eventos que possuam “Desenho” em seus títulos.

    Na janela Estágios do Pipeline dos Gráficos, a etapa do Assembler de Entrada mostra a geometria do objeto antes de sua transformação e a etapa do Sombreador do Vértice mostra o mesmo objeto depois que ele é transformado. Neste cenário, você sabe que você encontrou o objeto ausente quando ele é exibido no estágio Assembler de Entrada e nada é exibido na fase do estágio do Sombreador do Vértice.

    Dica

    Se outras fases de geometria - por exemplo, os estágios do Sombreador de Invólucro, o Sombreador de Domínio ou Sombreador de Geometria - processa o objeto, eles podem ser a causa do problema.Normalmente, o problema está relacionado à fase a mais recente em que o resultado não é exibido ou é exibido de uma maneira inesperada.

  4. Interromper quando você atingir a chamada de desenho que corresponde ao objeto ausente. Neste cenário, a janela Estágios do Pipeline dos Gráficos indica que a geometria foi emitida para GPU (indicado pela miniatura do Assembler de Entrada), mas não aparece no destino do renderizador porque algo deu errado durante o estágio do sombreador de vértice (indicado pela miniatura do Sombreador de Vértice):

    Um evento DrawIndexed e seu efeito sobre o pipeline

Depois de confirmar que o aplicativo emitiu uma chamada de desenho para a geometria do objeto ausente e descobriu que o problema ocorre durante a fase do sombreador de vértice, é possível usar o Depurador HLSL para examinar o sombreador de vértice e descobrir o que ocorreu à geometria do objeto. Você pode usar o depurador de HLSL para examinar o estado das variáveis de HLSL durante a execução, e avançar no código de HLSL e nos pontos de interrupção em conjunto para ajudá-lo a diagnosticar o problema.

Para examinar o sombreador do vértice

  1. Inicie a depuração do estágio do sombreador de vértice. Na janela Etapas do Pipeline dos Gráficos, na etapa de Sombreador do Vértice, escolha o botão de Iniciar Depuração.

  2. Como a fase Assembler de entrada aparece para fornecer dados bons para o sombreador de vértice e a fase Sombreador de vértice aparece para não produzir nenhuma saída, você deseja examinar a estrutura de saída do sombreador de vértice, output. Conforme você passa pelo código HLSL, obtém um visão aprofundada quando o output é alterado.

  3. A primeira vez que o output é modificado, o membro worldPos é gravado.

    O valor de "output.worldPos" aparece razoável

    Como seu valor parece ser razoável, você continua a depuração do código até a próxima linha que altera output.

  4. Na próxima vez em que o output for alterado, será escrito para o membro pos.

    O valor de "output.pos" foi zerado

    Dessa vez, o valor do membro pos — todos zeros — parecem suspeitos. Em seguida, você deseja determinar por que o valor de output.pos só tem zeros.

  5. Você observa que o output.pos adota seu valor de uma variável chamada temp. Na linha anterior, você pode ver que o valor de temp é o resultado da multiplicação de seu valor anterior por uma constante chamada projection. Você suspeita que o valor suspeito de tempé o resultado dessa multiplicação. Quando você posiciona o ponteiro em projection, você observa que seu valor também é todos os zeros.

    A matriz de projeção contém uma transformação incorreta

    Neste cenário, o exame revela que o valor suspeito tempé provavelmente causado por sua multiplicação por projection, e porque projection é uma constante que é feita para conter uma matriz de projeção, você sabendo que não deve conter todos os zeros.

Após determinar que a constante HLSL projection - passada para o sombreador pelo seu aplicativo - é a provável fonte do problema, a próxima etapa é localizar no seu código-fonte do aplicativo onde o buffer constante é preenchido. Você pode usar o Pilha de chamadas de eventos de elementos gráficos para localizar esse local.

Para localizar onde a constante é definida no código-fonte do seu app

  1. Abra a janela Pilha de Chamadas do Evento de Gráficos. Na barra de ferramentas Diagnóstico de Gráficos, escolha Pilha de Chamadas do Evento de Gráficos.

  2. Navegue para cima na pilha de chamadas até o código-fonte do aplicativo. Na janela Pilha de Chamadas de Eventos dos Gráficos, escolher a chamada mais elevada para ver se o buffer constante está sendo preenchido lá. Se não estiver, continuar até a pilha de chamadas até encontrar onde ela está sendo preenchida. Neste cenário, você descobre que o buffer constante está sendo preenchido - usando oDirect3D API UpdateSubresource - mais a pilha de chamadas em uma função que é nomeada MarbleMaze::Render, e que seu valor vem de um objeto constante de buffer que é chamado m_marbleConstantBufferData:

    O código que define os buffers de constantes do objeto

    Dica

    Se você está depurando simultaneamente seu aplicativo, você pode definir um ponto de interrupção neste local e ele será atingido quando o próximo quadro for processado.Você pode então inspecionar os membros de m_marbleConstantBufferData para confirmar que o valor do membro de projection é definido para todos zeros quando o buffer constante for preenchido.

Depois de localizar onde o buffer constante está sendo preenchido e descobrir que seus valores são provenientes da variável m_marbleConstantBufferData, a próxima etapa é localizar onde o membro m_marbleConstantBufferData.projection é definido para todos os zeros. Você pode usar Localizar todas as referências para verificação rapidamente para o código que altera o valor de m_marbleConstantBufferData.projection.

Para localizar onde o membro de projeção é definido no código-fonte do seu app

  1. Localizar referências para m_marbleConstantBufferData.projection. Abra o menu de atalho da variável m_marbleConstantBufferData e escolha Localizar Todas as Referências.

  2. Para navegar até o local da linha no código-fonte do seu app onde o membro projection é modificado, escolha a linha na janela Localizar Resultados de Símbolos . Como o primeiro resultado que altera o membro de projeção pode não ser a causa do problema, talvez seja necessário examinar várias áreas de código-fonte do seu aplicativo.

Depois de localizar onde o m_marbleConstantBufferData.projection está definido, você pode analisar o código-fonte ao redor para determinar a origem do valor incorreto. Nesse cenário, você descobre que o valor m_marbleConstantBufferData.projection é definido para uma variável local chamada projection antes de ser inicializada com um valor determinado pelo código m_camera->GetProjection(&projection); na próxima linha.

A projeção de mármore é definida antes da inicialização

Para corrigir o problema, você move a linha de código que define o valor de m_marbleConstantBufferData.projection após a linha que inicializa o valor da variável local projection.

O código-fonte C++ corrigido

Depois de corrigir o código, é possível reconstruir e executar o aplicativo novamente para descobrir que o problema de renderização está resolvido:

O objeto agora é exibido.