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:
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
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.
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:
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
Abra a janela Lista de Eventos de Gráficos.Na barra de ferramentas Diagnóstico de Gráficos, escolha Lista de Eventos.
Abra a janela Estágios de Pipeline Gráficos.Na barra de ferramentas Diagnóstico de Gráficos, escolha Estágios de Pipeline.
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.
Observação 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.
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):
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
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.
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.
A primeira vez que o output é modificado, o membro worldPos é gravado.
Como seu valor parece ser razoável, você continua a depuração do código até a próxima linha que altera output.
Na próxima vez em que o output for alterado, será escrito para o membro pos.
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.
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.
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
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.
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:
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
Localizar referências para m_marbleConstantBufferData.projection.Abra o menu de atalho da variável m_marbleConstantBufferData e escolha Localizar Todas as Referências.
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.
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.
Depois de corrigir o código, é possível reconstruir e executar o aplicativo novamente para descobrir que o problema de renderização está resolvido: