Esse artigo contém uma coleção de perguntas frequentes (FAQ) sobre o Microsoft DirectX.
Problemas gerais de desenvolvimento do DirectX
Os desenvolvedores de jogos devem realmente se preocupar em dar suporte a edições x64?
Com certeza. A tecnologia x64 está amplamente disponível no mercado. A maioria das novas CPUs vendidas nos últimos anos, e quase todas as linhas de processadores em desenvolvimento da AMD e Intel, são compatíveis com x64. O Windows XP Professional x64 Edition introduziu a tecnologia de habilitação do sistema operacional para x64 lançada em abril de 2005. Como as edições x64 exigem uma nova geração de drivers nativos de 64 bits, essa primeira versão foi limitada à distribuição OEM.
Com o Windows Vista, os clientes podem escolher edições de 32 bits ou 64 bits ao comprar computadores baseados no Windows, e as licenças para o Windows Vista são válidas para edições de 32 bits ou 64 bits do sistema operacional. Além disso, muitos drivers de 64 bits estão disponíveis na caixa, e os fabricantes de dispositivos são obrigados a fornecer drivers nativos de 32 bits e 64 bits como parte do Programa de Certificação do Windows.
Todos esses fatores aumentarão consideravelmente as implantações de edições de 64 bits do Windows. À medida que novos computadores começam a ser distribuídos com mais de 2 GB de RAM física, o incentivo para usar um sistema operacional de 32 bits diminui muito em favor das edições de 64 bits. A tecnologia de 64 bits suporta totalmente o código nativo de 32 bits, embora implementações nativas de 64 bits sejam necessárias para aproveitar ao máximo o novo espaço de memória de 64 bits. Todo aplicativo de 32 bits deve ter compatibilidade de 64 bits como um requisito mínimo de distribuição, e atender a esse requisito é um requisito de linha de base para compatibilidade com o Windows Vista. As incompatibilidades geralmente surgem do uso do código de 16 bits projetado para o sistema operacional Windows 3.1 ou da instalação de drivers que não são fornecidos em formatos nativos de 32 bits e 64 bits.
Para obter mais detalhes sobre a tecnologia de 64 bits, consulte Programação de 64 bits para Desenvolvedores de jogos.
Os desenvolvedores de jogos ainda devem publicar jogos para Windows 95, Windows 98 ou Windows ME?
Não mais, por dois motivos: desempenho e conjunto de recursos.
Se a velocidade mínima da CPU necessária para o seu jogo for de 1,2 GHz ou superior (o que é mais comum para títulos de alto desempenho), a grande maioria dos computadores elegíveis estará executando o Windows XP. Na época em que computadores com velocidades de CPU acima de 1,2 GHz estavam sendo vendidos, o Windows XP foi instalado como o sistema operacional padrão por quase todos os fabricantes. Isso significa que há muitos recursos encontrados no Windows XP que os desenvolvedores de jogos de hoje devem aproveitar, incluindo:
- Multitarefa melhorada: o que resulta em uma experiência melhor e mais suave para vídeo, áudio e jogos.
- Modelo de driver de vídeo mais estável: o que permite depuração mais fácil, jogo mais fluido e melhor desempenho.
- Configuração mais fácil para rede: o que facilita o acesso a jogos com vários jogadores.
- Suporte para transferências DMA por padrão de discos rígidos: o que resulta em aplicativos com carregamento mais suave e rápido.
- Relatório de erros do Windows: o que resulta em um sistema operacional, drivers e aplicativos mais estáveis.
- Suporte a Unicode: o que simplifica muito os problemas de localização.
- Mais segurança e estabilidade: o que resulta em melhores experiências do consumidor.
- Melhor suporte para hardware moderno: a maioria dos quais não usa mais drivers do Windows 98.
- Gerenciamento de memória aprimorado: o que resulta em mais estabilidade e segurança.
- Sistema de arquivos NTFS aprimorado: que é mais resistente a falhas e tem melhor desempenho com recursos de segurança.
Os desenvolvedores de jogos ainda devem publicar jogos para o Windows 2000?
Não mais. Além dos motivos listados em Os desenvolvedores de jogos ainda devem publicar jogos para Windows 95, Windows 98 ou Windows ME?, o Windows 2000 não tem esses recursos:
- O Windows XP oferece suporte a recursos avançados do processador, como Hyper-Threading, Multi-Core e x64.
- O Windows XP oferece suporte a componentes lado a lado, o que reduz significativamente os conflitos de controle de versão de aplicativos.
- O Windows XP oferece suporte à proteção de memória sem execução, o que ajuda a impedir programas mal-intencionados e pode ajudar na depuração.
- O Windows XP melhorou o suporte para placas de vídeo avançadas baseadas em AGP e PCI Express.
- O Windows XP suporta troca rápida de usuário, área de trabalho remota e assistência remota, o que pode ajudar a reduzir os custos de suporte ao produto.
- Ferramentas de desempenho como PIX (no SDK de Desenvolvedor do DirectX) não oferecem mais suporte ao Windows 2000.
Em suma, o Windows 2000 nunca foi projetado ou comercializado como um sistema operacional para consumidor.
Quais são as diferenças entre as várias edições do Windows Vista? Como elas afetam meu aplicativo DirectX?
A família Windows Vista inclui cinco edições:
- Windows Vista Home Basic
- Windows Vista Home Premium
- Windows Vista Business
- Windows Vista Enterprise
- Windows Vista Ultimate
Home Basic e Home Premium são versões focadas no consumidor, com recursos como o Microsoft Family Safety (anteriormente conhecido como Controles dos Pais), e o Home Premium inclui o Media Center. Business e Enterprise são edições focadas em empresas, com recursos como Ingresso no domínio e Área de Trabalho Remota/Serviços de Terminal. A edição Ultimate combina todos os recursos das edições para consumidores e corporativas em uma única versão. Todas as edições vêm em edições de 32 bits (x86) e 64 bits (x64), e os usuários podem usar o mesmo identificador de produto para ambas as plataformas.
A tecnologia subjacente às várias edições é idêntica e todas elas têm a mesma versão do tempo de execução do DirectX e de outros componentes. No entanto, as edições têm algumas pequenas diferenças em relação aos jogos:
- O Explorador de Jogos existe em todas as edições, mas o atalho Jogos no menu Iniciar existe apenas no Home Basic, Home Premium e Ultimate. O Explorador de Jogos ainda pode ser encontrado em todas as edições (clicando em Iniciar, apontando para Todos os Programas e depois clicando em Jogos) e as funções de interface IGameExplorer em todas as edições.
- Os jogos incluídos no Windows não estão disponíveis por padrão no Business e no Enterprise, mas podem ser habilitados pelo administrador.
- O Microsoft Family Safety e as classificações de jogos não exibem ou têm qualquer influência no comportamento do Business ou do Enterprise e são desativados no Ultimate quando um domínio é ingressado.
As configurações do Controle de Conta de Usuário têm os mesmos padrões em todas as edições, mas podem ser substituídas pelas configurações de Política de Grupo para o domínio no Business, Enterprise e Ultimate. Por exemplo, a configuração de política Controle de Conta de Usuário: comportamento do prompt de elevação para usuários padrão pode muito bem ser definida como Negar automaticamente solicitações de elevação em muitas configurações de negócios para aprimorar a segurança, e muitos usuários nesses ambientes sempre serão executados como usuários padrão sem a capacidade de escolher executar como Administrador. Qualquer programa (como um instalador) que exija direitos administrativos, seja devido à detecção de instalação herdada ou a ter um manifesto que especifica o nível de execução solicitado como "requireAdministrator", sempre falhará ao iniciar em tais situações. Outras configurações de política, como Controle de Conta de Usuário: somente elevar executáveis assinados e validados também podem impedir que o instalador funcione se você não assinar o arquivo executável usando o Authenticode.
Esses tipos de alterações de política podem ser aplicados a qualquer edição do Windows Vista, mas são mais prováveis em computadores que ingressaram em um domínio.
Quais são as diferenças entre as várias edições do Windows 7? Como elas afetam meu aplicativo DirectX?
A maioria dos usuários do Windows 7 provavelmente terá uma das duas edições: Windows 7 Home Premium, para usuários domésticos, ou Windows 7 Professional, para usuários empresariais e desenvolvedores. Para grandes empresas, há a edição licenciada por volume do Windows 7 Enterprise, que inclui todos os recursos do Windows 7. O Windows 7 Ultimate é o equivalente comercial dessa edição.
O Windows 7 Starter Edition está disponível em todo o mundo para OEMs e espera-se que seja implantado principalmente com netbooks, notebooks de ultrabaixo consumo de energia. O Windows 7 Home Basic está disponível apenas em mercados emergentes.
Observe que todas as edições do Windows 7 (exceto Starter Edition) estão disponíveis para versões de 32 bits (x86) e 64 bits (x64), e todos os pacotes comerciais do Windows 7 incluem mídia para ambas as versões. Assim como no Windows Vista, os usuários podem usar o mesmo identificador do produto de varejo em qualquer plataforma.
A tecnologia subjacente às várias edições é idêntica e todas as edições têm a mesma versão do tempo de execução do DirectX e de outros componentes. Eles têm algumas diferenças em relação aos recursos de jogos:
- O Explorador de Jogos existe em todas as edições, mas o atalho Jogos no menu Iniciar está oculto por padrão no Windows 7 Professional e Enterprise. O Explorador de Jogos ainda pode ser encontrado no menu Iniciar (clicando em Todos os Programas e clicando duas vezes em Jogos), e o atalho direto Jogos pode ser ativado pelo usuário.
- Os jogos incluídos no Windows não estão disponíveis por padrão no Windows 7 Professional e no Enterprise, mas podem ser habilitados pelo administrador.
- O Microsoft Family Safety e as classificações de jogos estão disponíveis em todas as edições, mas são desabilitadas no Windows 7 Professional, Enterprise e Ultimate quando o sistema operacional ingressa em um domínio. Assim como no Windows Vista Ultimate, esse recurso pode ser reativado no computador que ingressou em um domínio.
As configurações UAC (Controle de Conta de Usuário) podem ser afetadas pelas configurações de Política de Grupo nas edições Windows 7 Professional, Enterprise e Ultimate, assim como no Windows Vista. Para obter mais informações, confira Quais são as diferenças entre as várias edições do Windows Vista? Como elas afetam meu aplicativo DirectX?
O DirectX 10 estará disponível para o Windows XP?
Não. O Windows Vista, que tem o DirectX 10, inclui um tempo de execução atualizado do DirectX com base no tempo de execução no Windows XP SP2 (DirectX 9.0c) com alterações para funcionar com o novo WDDM (Windows Display Driver Model) e a nova pilha de drivers de áudio, além de outras atualizações no sistema operacional. Além do Direct3D 9, o Windows Vista oferece suporte a duas novas interfaces quando o hardware de vídeo e os drivers corretos estão presentes: Direct3D9Ex e Direct3D10.
Como essas novas interfaces dependem da tecnologia WDDM, elas nunca estarão disponíveis em versões anteriores do Windows. Todas as outras alterações feitas nas tecnologias DirectX para o Windows Vista também são específicas para a nova versão do Windows. O nome DirectX 10 é enganoso na medida em que muitas tecnologias fornecidas no SDK do DirectX (XACT, XINPUT, D3DX) não são englobadas por esse número de versão. Assim, referir-se ao número de versão do tempo de execução do DirectX como um todo perdeu muito de seu significado, mesmo para o 9.0c. A ferramenta de diagnóstico do DirectX (DXdiag.exe) no Windows Vista relata o DirectX 10, mas isso realmente se refere apenas ao Direct3D 10.
O DirectX 11 estará disponível para o Windows Vista ou o Windows XP?
O DirectX 11 está integrado no Windows 7 e está disponível como uma atualização para o Windows Vista (consulte https://go.microsoft.com/fwlink/p/?linkid=160189). Isso inclui a API do Direct3D 11, o DXGI 1.1 (DirectX Graphic Infrastructure), os níveis de recursos 10Level9, o dispositivo de renderização de software WARP 10 (Windows Advanced Rasterization Platform), o Direct2D, o DirectWrite e uma atualização da API do Direct3D 10.1 para oferecer suporte ao 10Level9 e ao WARP 10.
Pelas mesmas razões observadas na pergunta anterior (O DirectX 10 estará disponível para o Windows XP?), o Direct3D 11 e APIs relacionadas não estão disponíveis no Windows XP.
O que aconteceu com o DirectShow? Não consigo encontrá-lo no SDK do DirectX.
O DirectShow foi removido do SDK do DirectX em abril de 2005. Você pode obter os cabeçalhos, bibliotecas, ferramentas e exemplos do DirectShow no SDK do Windows (anteriormente conhecido como SDK da Plataforma). O DirectSetup no SDK do DirectX continua a oferecer suporte à redistribuição dos componentes de sistema do DirectShow e os componentes mais recentes já estão instalados nos seguintes sistemas operacionais: Microsoft Windows XP Service Pack 2, Windows XP Professional x64 Edition, Windows Server 2003 Service Pack 1 e Windows Vista.
Que alterações foram feitas no tempo de execução do DirectX para o Windows Vista?
As principais alterações foram feitas para oferecer suporte ao novo WDDM. Para obter detalhes sobre o novo modelo de driver, sobre os impactos no Direct3D 9 e nas duas novas interfaces gráficas, Direct3D 9Ex e Direct3D 10, consulte APIs de elementos gráficos no Windows. Novas APIs de elementos gráficos para o Windows 7 — Direct3D 11, Direct2D, DirectWrite, DXGI 1.1 e um Direct3D 10.1 atualizado — estão disponíveis como uma atualização para o Windows Vista (consulte https://go.microsoft.com/fwlink/p/?linkid=160189).
O Windows Vista Service Pack 1 inclui uma versão atualizada do tempo de execução do DirectX. Essa atualização estende o suporte do Windows Vista para incluir o Direct3D 10.1, expondo novos recursos de hardware opcionais. (Todo o hardware capaz de suportar o Direct3D 10.1 também suporta totalmente todas as funcionalidades do Direct3D 10.)
O DirectSound foi atualizado para expor os recursos da nova pilha de drivers de áudio do Windows Vista, que oferece suporte a buffers de software multicanal. A API do modo retido do Direct3D foi completamente removida do Windows Vista. O DirectPlay Voice também foi removido, assim como o NAT Helper do DirectPlay e a interface do usuário do mapeador de ações do DirectInput. Suporte para as interfaces do DirectX 7 e do DirectX 8 para o Visual Basic 6.0 não está disponível no Windows Vista.
Que alterações foram feitas no tempo de execução do DirectX para o Windows 7?
O Windows 7 inclui todos os componentes do tempo de execução do DirectX encontrados no Windows Vista e adiciona os níveis de recursos Direct3D 11, DXGI 1.1, 10Level9, o dispositivo de software WARP10, Direct2D, DirectWrite e uma atualização para o Direct3D 10.1 para oferecer suporte ao 10Level9 e ao WARP10. Para obter mais informações, consulte APIs de elementos gráficos no Windows.
Todos os outros componentes são idênticos ao Windows Vista, com a adição de suporte nativo de 64 bits (x64) para a API principal do DirectMusic relacionada à interface MIDI com carimbo de data/hora. A camada de desempenho do DirectMusic permanece preterida e só está disponível para aplicativos de 32 bits no Windows 7 para compatibilidade do aplicativo. Observe que o suporte nativo de 64 bits do DirectMusic não está disponível no Windows Vista.
Acho que encontrei um bug de driver, o que eu faço?
Primeiro, verifique os resultados com o Rasterizador de referência. Em seguida, verifique os resultados com a versão mais recente com certificado WHQL do driver IHVs. Você pode verificar programaticamente o status do WHQL usando o método GetAdapterIdentifier() na interface IDirect3D9 passando o sinalizador D3DENUM_WHQL_LEVEL.
Por que recebo tantas mensagens de erro quando tento compilar os exemplos?
Você provavelmente não tem seu caminho de inclusão definido corretamente. Muitos compiladores, incluindo o Microsoft Visual C++, incluem uma versão anterior do SDK, portanto, se o caminho de inclusão pesquisar o compilador padrão incluir diretórios primeiro, você obterá versões incorretas dos arquivos de cabeçalho. Para corrigir esse problema, verifique se o caminho de inclusão e os caminhos de biblioteca estão definidos para pesquisar os caminhos de inclusão e biblioteca do Microsoft DirectX primeiro. Consulte também o arquivo dxreadme.txt no SDK. Se você instalar o SDK do DirectX e estiver usando o Visual C++, o instalador pode opcionalmente configurar os caminhos de inclusão para você.
Recebo erros de vinculador sobre símbolos ausentes ou múltiplos para GUIDs (identificadores globais exclusivos), o que faço?
Os vários GUIDs que você usa devem ser definidos uma vez e apenas uma vez. A definição do GUID será inserida se você #define o símbolo INITGUID antes de incluir os arquivos de cabeçalho do DirectX. Portanto, você deve certificar-se de que isso ocorre apenas para uma unidade de compilação. Uma alternativa a esse método é vincular com a biblioteca dxguid.lib, que contém definições para todos os GUIDs do DirectX. Se você usar esse método (que é recomendado), então você nunca #define o símbolo INITGUID.
Posso converter um ponteiro para uma interface DirectX para um número de versão inferior?
Não. As interfaces do DirectX são interfaces COM. Isso significa que não há exigência de que interfaces numeradas superiores sejam derivadas de interfaces numeradas inferiores correspondentes. Portanto, a única maneira segura de obter uma interface diferente para um objeto DirectX é usar o método QueryInterface da interface. Esse método faz parte da interface IUnknown padrão, da qual todas as interfaces COM devem derivar.
Posso misturar o uso de componentes do DirectX 9 e DirectX 8 ou componentes anteriores no mesmo aplicativo?
Você pode misturar livremente diferentes componentes de diferentes versões. Por exemplo, você pode usar DirectInput 8 com Direct3D 9 no mesmo aplicativo. No entanto, você geralmente não pode misturar versões diferentes do mesmo componente dentro do mesmo aplicativo. Por exemplo, você não pode misturar o DirectDraw 7 com o Direct3D 9 (uma vez que esses são efetivamente o mesmo componente que o DirectDraw foi incluído no Direct3D a partir do DirectX 8). No entanto, há exceções, como o uso do Direct3D 9 e do Direct3D 10 juntos no mesmo aplicativo, o que é permitido.
Posso misturar o uso do Direct3D 9 e do Direct3D 10 no mesmo aplicativo?
Sim, você pode usar essas versões do Direct3D juntas no mesmo aplicativo.
O que significam os valores de retorno dos métodos Release ou AddRef?
O valor de retorno será a contagem de referência atual do objeto. No entanto, a especificação COM afirma que você não deve confiar nisso e o valor geralmente só está disponível para fins de depuração. Os valores observados podem ser inesperados, pois vários outros objetos do sistema podem estar mantendo referências aos objetos DirectX criados. Por esse motivo, você não deve escrever código que chama repetidamente Release até que a contagem de referência seja zero, pois o objeto pode ser liberado mesmo que outro componente ainda possa estar fazendo referência a ele.
É importante em que ordem eu libero as interfaces DirectX?
Não deve importar porque as interfaces COM são contagens de referência. No entanto, existem alguns bugs conhecidos com a ordem de liberação das interfaces em algumas versões do DirectX. Por segurança, você é aconselhado a liberar interfaces em ordem de criação inversa quando possível.
O que é um ponteiro inteligente e devo usá-lo?
Um ponteiro inteligente é uma classe de modelo C++ projetada para encapsular a funcionalidade do ponteiro. Em particular, existem classes de ponteiro inteligente padrão projetadas para encapsular ponteiros de interface COM. Esses ponteiros executam automaticamente QueryInterface em vez de uma conversão e eles lidam com AddRef e Release para você. Se você deve usá-los é em grande parte uma questão de gosto. Se o seu código contém muitas cópias de ponteiros de interface, com vários AddRefs e Releases, então os ponteiros inteligentes provavelmente podem tornar seu código mais limpo e menos propenso a erros. Caso contrário, você pode ficar sem eles. O Visual C++ inclui um ponteiro inteligente COM padrão da Microsoft, definido no arquivo de cabeçalho "comdef.h" (procure com_ptr_t na ajuda).
Como resolver os problemas na depuração do meu aplicativo DirectX?
O problema mais comum com a depuração de aplicativos DirectX é tentar depurar enquanto uma superfície do DirectDraw está bloqueada. Essa situação pode causar um "Win16 Lock" em sistemas Microsoft Windows 9x, que impede a janela do depurador de pintar. Especificar o sinalizador de D3DLOCK_NOSYSLOCK ao bloquear a superfície geralmente pode eliminar isso. O Windows 2000 não é afetado com esse problema. Ao desenvolver um aplicativo, é útil estar executando a versão de depuração do tempo de execução do DirectX (selecionada quando você instala o SDK), que executa algumas validações de parâmetros e envia mensagens úteis para a saída do depurador.
Qual é a maneira correta de verificar os códigos de devolução?
Use as macros SUCCEEDED e FAILED. Os métodos DirectX podem retornar vários códigos de sucesso e falha, portanto, simples:
== D3D_OK
ou um teste semelhante nem sempre será suficiente.
Como fazer para desativar ALT+TAB e outras alternâncias de tarefas?
Você não desabilita! Os jogos devem conseguir lidar com a troca de tarefas, pois muitas coisas fazem com que isso aconteça: ALT+TAB, conexões de área de trabalho remota, Troca Rápida de Usuário, limites de uso do Controles dos Pais e muitos outros eventos.
Ao mesmo tempo, duas fontes comuns de alternância acidental de tarefas em jogos com esquemas de controle centrados no teclado são pressionar a tecla do logotipo do Windows e ativar o recurso de acessibilidade StickyKeys com a tecla SHIFT. Para resolver esses casos desabilitando a funcionalidade, consulte as técnicas descritas em Desabilitar teclas de atalho em jogos.
Existe algum livro recomendado explicando COM?
Inside COM de Dale Rogerson, publicado pela Microsoft Press, é uma excelente introdução ao COM. Para saber mais detalhes sobre o COM, o livro Essential COM de Don Box, publicado pela Longman, também é altamente recomendado.
O que é código gerenciado?
Código gerenciado é o código que tem sua execução gerenciada pelo CLR (Common Language Runtime) do .NET Framework. Refere-se a um contrato de cooperação entre o código que executa nativamente e o tempo de execução. Esse contrato especifica que, em qualquer ponto de execução, o tempo de execução pode interromper uma CPU em execução e recuperar informações específicas do endereço de instrução da CPU atual. As informações que devem ser consultáveis geralmente pertencem ao estado de tempo de execução, como o conteúdo de memória de pilha ou registro.
Antes que o código seja executado, o nível de integridade é compilado em código executável nativo. E, como essa compilação acontece pelo ambiente de execução gerenciado (ou, mais corretamente, por um compilador com reconhecimento do tempo de execução que sabe como direcionar o ambiente de execução gerenciado), o ambiente de execução gerenciado pode fazer garantias sobre o que o código vai fazer. Ele pode inserir interceptações e ganchos de coleta de lixo apropriados, manipulação de exceções, segurança de tipos, limites de matriz e verificação de índice, e assim por diante. Por exemplo, esse compilador se certifica de dispor registro de ativação e tudo para que o coletor de lixo possa ser executado em segundo plano em um thread separado, andando constantemente pela pilha de chamadas ativa, encontrando todas as raízes, perseguindo todos os objetos vivos. Além disso, como o nível de integridade tem uma noção de segurança do tipo, o mecanismo de execução manterá a garantia de segurança do tipo, eliminando uma classe completa de erros de programação que muitas vezes levam a falhas de segurança.
Em contraste com o mundo não gerenciado: arquivos executáveis não gerenciados são basicamente uma imagem binária, código x86, carregado na memória. O contador de programas é colocado lá e esse é o último que o sistema operacional conhece. Existem proteções em vigor em torno do gerenciamento de memória e E/S de porta e assim por diante, mas o sistema realmente não sabe o que o aplicativo está fazendo. Portanto, ele não pode fazer nenhuma garantia sobre o que acontece quando o aplicativo é executado.
Que livros existem sobre programação geral do Windows?
Vários. No entanto, os dois que são altamente recomendados são:
- Programming Windows por Charles Petzold (Microsoft Press)
- Programming Applications for Windows por Jeffrey Richter (Microsoft Press)
Como fazer para depurar usando os arquivos de símbolo do Windows?
A Microsoft publica símbolos removidos para todas as DLLs do sistema (além de algumas outras). Para acessá-los, adicione o seguinte ao caminho do símbolo nas configurações do projeto dentro do Visual Studio:
srv*https://msdl.microsoft.com/download/symbols
para armazenar símbolos em cache localmente, use a seguinte sintaxe:
srv*c:\cache*https://msdl.microsoft.com/download/symbols
Onde c:\cache é um diretório local para armazenar em cache arquivos de símbolo.
Perguntas sobre o Direct3D
Perguntas gerais sobre o Direct3D
Onde posso encontrar informações sobre técnicas de gráficos 3D?
O livro padrão sobre o assunto é o Computer Graphics: Principles and Practice por Foley, Van Dam et al. É um recurso valioso para quem quer entender os fundamentos matemáticos das técnicas de geometria, rasterização e iluminação. Perguntas frequentes sobre o grupo Usenet comp.graphics.algorithms também contém material útil.
O Direct3D emula funcionalidades não fornecidas pelo hardware?
Depende. O Direct3D tem um pipeline de processamento de vértice de software completo (incluindo suporte para sombreadores de vértice personalizados). No entanto, nenhuma emulação é fornecida para operações de nível de pixel. Os aplicativos devem verificar os bits de limite apropriados e usar a API ValidateDevice para determinar o suporte.
Existe um rasterizador de software incluído no Direct3D?
Não para aplicativos de desempenho. Um rasterizador de referência é fornecido para validação do driver, mas a implementação é projetada para precisão e não para o desempenho. O Direct3D oferece suporte a rasterizadores de software de plug-in.
Como posso executar o Chroma-Key com elementos gráficos do DirectX?
O Chroma-Key não é suportado diretamente, em vez disso, você terá que usar a mistura alfa para emular o Chroma-Key. A função D3DXCreateTextureFromFileEx() pode ser usada para facilitar isso. Essa função aceita um parâmetro de cor de chave e substituirá todos os pixels da imagem de origem que contém a cor especificada por pixels pretos transparentes na textura criada.
O código de geometria do Direct3D utiliza instruções SIMD do 3DNow! e/ou do Pentium III?
Sim. O pipeline de geometria do Direct3D tem vários caminhos de código diferentes, dependendo do tipo de processador, e utilizará as operações especiais de ponto flutuante fornecidas por instruções SIMD do 3DNow! ou do Pentium III quando disponíveis. Isso inclui o processamento de sombreadores de vértice personalizados.
Como fazer para evitar que pixels transparentes sejam gravados no buffer z?
Você pode filtrar pixels com um valor alfa acima ou abaixo de um determinado limite. Você controla esse comportamento usando os estados de renderização ALPHATESTENABLE, ALPHAREF e ALPHAFUNC.
O que é um buffer de estêncil?
Um buffer de estêncil é um buffer adicional de informações por pixel, muito parecido com um buffer z. Na verdade, ele reside em alguns dos bits de um buffer z. Os formatos comuns de estêncil/buffer z são o z de 15 bits e o estêncil de 1 bit ou o z de 24 bits ou o estêncil de 8 bits. É possível executar operações aritméticas simples no conteúdo do buffer de estêncil por pixel à medida que os polígonos são renderizados. Por exemplo, o buffer de estêncil pode ser incrementado ou diminuído, ou o pixel pode ser rejeitado se o valor do estêncil falhar em um teste de comparação simples. Isso é útil para efeitos que envolvem a marcação de uma região do buffer de quadro e, em seguida, a execução da renderização apenas da região marcada (ou não marcada). Bons exemplos são efeitos volumétricos como volumes de sombra.
Como usar um buffer de estêncil para renderizar volumes de sombra?
A chave para esse e outros efeitos de buffer de estêncil volumétrico é a interação entre o buffer de estêncil e o buffer z. Uma cena com um volume de sombra é renderizada em três estágios. Primeiro, a cena sem a sombra é renderizada como de costume, usando o buffer z. Em seguida, a sombra é marcada no buffer de estêncil da seguinte maneira. As faces frontais do volume de sombra são desenhadas usando polígonos invisíveis, com o teste z habilitado, mas as gravações z desabilitadas e o buffer de estêncil incrementado a cada pixel que passa no teste z. As faces traseiras do volume de sombra são renderizadas de forma semelhante, mas diminuindo o valor do estêncil.
Agora, considere um único pixel. Supondo que a câmera não esteja no volume de sombra, há quatro possibilidades para o ponto correspondente na cena. Se o raio da câmera até o ponto não cruzar o volume de sombra, nenhum polígono de sombra terá sido desenhado lá e o buffer de estêncil ainda será zero. Caso contrário, se o ponto estiver na frente do volume de sombra, os polígonos de sombra terão saída no buffer z e o estêncil permanecerá novamente inalterado. Se os pontos estiverem atrás do volume de sombra, o mesmo número de faces de sombra frontal que as faces traseiras terá sido renderizado e o estêncil será zero, tendo sido incrementado tantas vezes quanto diminuído.
A última possibilidade é que o ponto esteja dentro do volume da sombra. Nesse caso, a face traseira do volume de sombra terá saída no buffer z, mas não a face frontal, portanto, o buffer de estêncil será um valor diferente de zero. O resultado é que partes do buffer de quadro na sombra têm valor de estêncil diferente de zero. Finalmente, para realmente renderizar a sombra, toda a cena é cobertada com um polígono alfa-misturado definido para afetar apenas pixels com valor de estêncil diferente de zero. Um exemplo dessa técnica pode ser visto no exemplo "Volume de sombra" que acompanha o SDK do DirectX.
Quais são as regras de alinhamento texel? Como fazer para obter um mapeamento um-para-um?
Isso é explicado detalhadamente na documentação do Direct3D 9. No entanto, o resumo executivo é que você deve enviesar suas coordenadas de tela por -0,5 de um pixel, a fim de alinhar corretamente com texels. A maioria das placas agora está em conformidade com as regras de alinhamento texel, no entanto, existem algumas placas ou drivers mais antigos que não estão. Para lidar com esses casos, o melhor conselho é entrar em contato com o fornecedor de hardware em questão e solicitar drivers atualizados ou sua solução alternativa sugerida. Observe que no Direct3D 10, essa regra não é mais válida.
Qual é o objetivo do sinalizador D3DCREATE\_PUREDEVICE?
Use o sinalizador D3DCREATE_PUREDEVICE durante a criação do dispositivo para criar um dispositivo puro. Um dispositivo puro não salva o estado atual (durante as alterações de estado), o que geralmente melhora o desempenho. Esse dispositivo também requer processamento de vértice de hardware. Um dispositivo puro normalmente é usado quando o desenvolvimento e a depuração são concluídos, e você deseja obter o melhor desempenho.
Uma desvantagem de um dispositivo puro é que ele não suporta todas as chamadas de API Get*. Isso significa que você não pode usar um dispositivo puro para consultar o estado do pipeline. Isso torna mais difícil depurar durante a execução de um aplicativo. Abaixo está uma lista de todos os métodos que são desativados por um dispositivo puro.
- IDirect3DDevice9::GetClipPlane
- IDirect3DDevice9::GetClipStatus
- IDirect3DDevice9::GetLight
- IDirect3DDevice9::GetLightEnable
- IDirect3DDevice9::GetMaterial
- IDirect3DDevice9::GetPixelShaderConstantF
- IDirect3DDevice9::GetPixelShaderConstantI
- IDirect3DDevice9::GetPixelShaderConstantB
- IDirect3DDevice9::GetRenderState
- IDirect3DDevice9::GetSamplerState
- IDirect3DDevice9::GetTextureStageState
- IDirect3DDevice9::GetTransform
- IDirect3DDevice9::GetVertexShaderConstantF
- IDirect3DDevice9::GetVertexShaderConstantI
- IDirect3DDevice9::GetVertexShaderConstantB
Uma segunda desvantagem de um dispositivo puro é que ele não filtra nenhuma alteração de estado redundante. Ao usar um dispositivo puro, seu aplicativo deve reduzir o número de alterações de estado no loop de renderização ao mínimo. Isso pode incluir a filtragem de alterações de estado para garantir que os estados não sejam definidos mais de uma vez. Essa compensação depende do aplicativo; se você usar mais de 1.000 chamadas Set por quadro, considere aproveitar a filtragem de redundância que é feita automaticamente por um dispositivo não puro.
Como acontece com todos os problemas de desempenho, a única maneira de saber se seu aplicativo terá ou não um desempenho melhor com um dispositivo puro é comparar o desempenho do aplicativo com um dispositivo puro versus não puro. Um dispositivo puro tem o potencial de acelerar um aplicativo reduzindo a sobrecarga de CPU da API. Mas tenha cuidado! Para alguns cenários, um dispositivo puro tornará seu aplicativo mais lento (devido ao trabalho adicional da CPU causado por alterações de estado redundantes). Se você não tiver certeza de qual tipo de dispositivo funcionará melhor para seu aplicativo e você não filtra alterações redundantes no aplicativo, use um dispositivo não puro.
Como enumerar os dispositivos de vídeo em um sistema de vários monitores?
A enumeração pode ser executada por meio de uma iteração simples pelo aplicativo usando métodos da interface IDirect3D9. Chame GetAdapterCount para determinar o número de placas de vídeo no sistema. Chame GetAdapterMonitor para determinar a qual monitor físico uma placa está conectada (esse método retorna um HMONITOR, que você pode usar na API Win32 GetMonitorInfo para determinar informações sobre o monitor físico). Determinar as características de uma placa de vídeo específica ou criar um dispositivo Direct3D nessa placa é tão simples quanto passar o número da placa apropriada no lugar de D3DADAPTER_DEFAULT ao chamar GetDeviceCaps, CreateDevice ou outros métodos.
O que aconteceu com o bump mapping de função fixa no D3D9?
A partir do Direct3D 9, limitamos a validação em placas que só podem suportar > 2 texturas simultâneas. Algumas placas mais antigas têm apenas 3 estágios de textura disponíveis quando você usa uma operação de modulação alfa específica. O uso mais comum para o qual as pessoas usam os 3 estágios é fazer bump mapping em relevo, e você ainda pode fazer isso com o D3D9.
O campo de altura deve ser armazenado no canal alfa e é usado para modular a contribuição das luzes, ou seja:
// Stage 0 is the base texture, with the height map in the alpha channel
m_pd3dDevice->SetTexture(0, m_pEmbossTexture );
m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0 );
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE );
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
if( m_bShowEmbossMethod )
{
// Stage 1 passes through the RGB channels (SELECTARG2 = CURRENT), and
// does a signed add with the inverted alpha channel.
// The texture coords associated with Stage 1 are the shifted ones, so
// the result is:
// (height - shifted_height) * tex.RGB * diffuse.RGB
m_pd3dDevice->SetTexture( 1, m_pEmbossTexture );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1 );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_ADDSIGNED );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE|D3DTA_COMPLEMENT );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT );
// Set up the alpha blender to multiply the alpha channel
// (monochrome emboss) with the src color (lighted texture)
m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
}
Esse exemplo, juntamente com outros exemplos mais antigos, não são mais fornecidos na versão atual do SDK e não serão enviados em versões futuras do SDK.
Processamento de geometria (vértice)
Os fluxos de vértice são confusos. Como eles funcionam?
O Direct3D monta cada vértice que é alimentado na parte de processamento do pipeline a partir de um ou mais fluxos de vértice. Ter apenas um fluxo de vértices corresponde ao antigo modelo antes do DirectX 8, no qual os vértices vêm de uma única fonte. Com o DirectX 8, diferentes componentes de vértice podem vir de diferentes fontes. Por exemplo, um buffer de vértices poderia conter posições e normais, enquanto um segundo mantinha valores de cor e coordenadas de textura.
O que é um sombreador de vértice?
Um sombreador de vértice processa um único vértice. Ele é definido usando uma linguagem simples semelhante a assembly que é montada pela biblioteca de utilitários D3DX em um fluxo de token que o Direct3D aceita. O sombreador de vértice toma como entrada um único vértice e um conjunto de valores constantes. Ele produz uma posição de vértice (no espaço de recorte) e, opcionalmente, um conjunto de cores e coordenadas de textura, que são usadas na rasterização. Observe que, quando você tem um sombreador de vértice personalizado, os componentes de vértice não têm mais nenhuma semântica aplicada a eles pelo Direct3D e os vértices são simplesmente dados arbitrários que são interpretados pelo sombreador de vértice criado.
Um sombreador de vértice executa recorte ou divisão de perspectiva?
Não. O sombreador de vértice produz uma coordenada homogênea no espaço de recorte para a posição de vértice transformada. A divisão de perspectiva e o recorte são realizados automaticamente após o sombreador.
Posso gerar geometria com um sombreador de vértice?
Um sombreador de vértice não pode criar ou destruir vértices. Ele opera em um único vértice de cada vez, tomando um vértice não processado como entrada e emitindo um único vértice processado. Ele pode, portanto, ser usado para manipular a geometria existente (aplicando deformações ou realizando operações de capa), mas não pode realmente gerar nova geometria em si.
Posso aplicar um sombreador de vértice personalizado aos resultados do pipeline de geometria de função fixa (ou vice-versa)?
Não. Você tem que escolher um ou o outro. Se você estiver usando um sombreador de vértice personalizado, será responsável por executar toda a transformação de vértice.
Posso usar um sombreador de vértice personalizado se meu hardware não oferecer suporte a ele?
Sim. O mecanismo de processamento de vértice do software Direct3D oferece suporte total a sombreadores de vértice personalizados com um nível surpreendentemente alto de desempenho.
Como posso determinar se o hardware suporta o meu sombreador de vértice personalizado?
Os dispositivos capazes de suportar sombreadores de vértice no hardware são obrigados a preencher o campo D3DCAPS9::VertexShaderVersion para indicar o nível de versão do sombreador de vértice que suportam. Qualquer dispositivo que pretenda oferecer suporte a um nível específico de sombreador de vértice deve oferecer suporte a todos os sombreadores de vértice legais que atendam à especificação para esse nível ou abaixo.
Quantos registros constantes estão disponíveis para sombreadores de vértice?
Os dispositivos que suportam sombreadores de vértice vs 1.0 são necessários para suportar um mínimo de 96 registros constantes. Os dispositivos podem suportar mais do que esse número mínimo e podem relatar isso por meio do campo D3DCAPS9::MaxVertexShaderConst.
Posso compartilhar dados de posição entre vértices com coordenadas de textura diferentes?
O exemplo comum dessa situação é um cubo no qual você deseja usar uma textura diferente para cada face. Infelizmente a resposta é não, atualmente não é possível indexar os componentes do vértice de forma independente. Mesmo com vários fluxos de vértice, todos os fluxos são indexados juntos.
Quando envio uma lista indexada de primitivos, o Direct3D processa todos os vértices no buffer ou apenas os que indexei?
Ao usar o pipeline de geometria de software, o Direct3D primeiro transforma todos os vértices no intervalo enviado, em vez de transformá-los "sob demanda" à medida que são indexados. Para dados densamente compactados (isto é, onde a maioria dos vértices são usados) isso é mais eficiente, principalmente quando as instruções SIMD estão disponíveis. Se seus dados estiverem compactados de forma esparsa (ou seja, muitos vértices não forem usados), convém considerar a reorganização dos dados para evitar muitas transformações redundantes. Ao usar a aceleração de geometria de hardware, os vértices são normalmente transformados sob demanda conforme necessário.
O que é um buffer de índice?
Um buffer de índice é exatamente análogo a um buffer de vértice, mas em vez disso, ele contém índices para uso em chamadas DrawIndexedPrimitive. É altamente recomendável que você use buffers de índice em vez de memória bruta alocada por aplicativo quando possível, pelos mesmos motivos que buffers de vértices.
Percebo que os índices de 32 bits são um tipo suportado. Posso usá-los em todos os dispositivos?
Não. Você deve verificar o campo D3DCAPS9::MaxVertexIndex para determinar o valor máximo de índice que é suportado pelo dispositivo. Esse valor deve ser maior que 2 elevado a 16ª potência -1 (0xffff) para que os buffers de índice do tipo D3DFMT_INDEX32 sejam suportados. Além disso, observe que alguns dispositivos podem oferecer suporte a índices de 32 bits, mas suportam um valor máximo de índice menor que 2 elevado a 32ª potência -1 (0xffffffff). Nesse caso, o aplicativo deve respeitar o limite informado pelo dispositivo.
O processamento de vértice S/W suporta 64 bits?
Há um pipeline de vértice s/w otimizado para x64, mas ele não existe para IA64.
Ajuste de desempenho
Como posso melhorar o desempenho do meu aplicativo Direct3D?
A seguir estão as principais áreas a serem analisadas ao otimizar o desempenho:
Tamanho do lote
O Direct3D é otimizado para grandes lotes de primitivos. Quanto mais polígonos puderem ser enviados em uma única chamada, melhor. Uma boa regra prática é visar uma média de 1.000 vértices por chamada primitiva. Abaixo desse nível, você provavelmente não está obtendo o desempenho ideal, acima disso e está em retornos decrescentes e potenciais conflitos com considerações de simultaneidade (veja abaixo).
Alterações de estado
Alterar o estado de renderização pode ser uma operação cara, especialmente ao alterar a textura. Por esse motivo, é importante minimizar ao máximo o número de alterações de estado feitas por quadro. Além disso, tente minimizar as alterações de buffer de vértice ou de índice.
Observação
A partir do DirectX 8, o custo de alterar o buffer de vértice não é tão caro quanto era com as versões anteriores, mas ainda é uma boa prática evitar alterações de buffer de vértice sempre que possível.
Simultaneidade
Se você puder organizar a execução de renderização simultaneamente com outro processamento, então você estará aproveitando ao máximo o desempenho do sistema. Essa meta pode entrar em conflito com a meta de reduzir as alterações de estado de renderização. Você precisa encontrar um equilíbrio entre o envio em lote para reduzir as alterações de estado e enviar dados para o driver mais cedo para ajudar a alcançar a simultaneidade. O uso de vários buffers de vértice de forma round-robin pode ajudar com a simultaneidade.
Uploads de textura
O upload de texturas para o dispositivo consome largura de banda e causa uma competição de largura de banda com dados de vértice. Portanto, é importante não comprometer demais a memória de textura, o que forçaria seu esquema de cache a carregar quantidades excessivas de texturas a cada quadro.
Buffers de vértice e de índice
Você sempre deve usar buffers de vértice e de índice, em vez de blocos simples de memória alocada do aplicativo. No mínimo, a semântica de bloqueio para buffers de vértice e de índice pode evitar uma operação de cópia redundante. Com alguns drivers, o buffer de vértice ou de índice pode ser colocado na memória mais ideal (talvez na memória de vídeo ou AGP) para acesso pelo hardware.
Blocos de macro de estado
Eles foram introduzidos no DirectX 7.0. Eles fornecem um mecanismo para registrar uma série de mudanças de estado (incluindo iluminação, material e mudanças de matriz) em uma macro, que pode ser reproduzida por uma única chamada. Isso apresenta duas vantagens:
- Você reduz a sobrecarga de chamadas fazendo uma chamada em vez de muitas.
- Um driver consciente pode pré-analisar e pré-compilar as alterações de estado, tornando muito mais rápido o envio para o hardware gráfico.
As alterações de estado ainda podem ser caras, mas o uso de macros de estado pode ajudar a reduzir pelo menos parte do custo. Use apenas um único dispositivo Direct3D. Se você precisar renderizar para vários destinos, use SetRenderTarget. Se você estiver criando um aplicativo em janela com várias janelas 3D, use a API CreateAdditionalSwapChain. O tempo de execução é otimizado para um único dispositivo e há uma penalidade de velocidade considerável para o uso de vários dispositivos.
Quais tipos primitivos (faixas, leques, listas e assim por diante) devo usar?
Muitas malhas encontradas em dados reais apresentam vértices que são compartilhados por vários polígonos. Para maximizar o desempenho, é desejável reduzir a duplicação em vértices transformados e enviados através do barramento para o dispositivo de renderização. É claro que o uso de listas de triângulos simples não alcança compartilhamento de vértices, tornando-se o método menos ideal. A escolha é entre usar faixas e leques, que implicam uma relação de conectividade específica entre polígonos e usar listas indexadas. Onde os dados naturalmente ficam em faixas e leques, esses são a escolha mais adequada, pois minimizam os dados enviados ao driver. No entanto, a decomposição de malhas em faixas e leques geralmente resulta em um grande número de peças separadas, implicando um grande número de chamadas DrawPrimitive. Por esse motivo, o método mais eficiente geralmente é usar uma única chamada DrawIndexedPrimitive com uma lista de triângulos. Uma vantagem adicional de usar uma lista indexada é que um benefício pode ser obtido mesmo quando triângulos consecutivos compartilham apenas um único vértice. Em resumo, se seus dados naturalmente ficarem em grandes faixas ou leques, use faixas ou leques; caso contrário, use listas indexadas.
Como você determina a memória de textura total que uma placa tem, excluindo a memória AGP?
IDirect3DDevice9::GetAvailableTextureMem retorna o total de memória disponível, incluindo AGP. Alocar recursos com base em uma suposição de quanta memória de vídeo você tem não é uma boa ideia. Por exemplo, e se a placa estiver sendo executada em UMA (Arquitetura de Memória Unificada) ou for capaz de compactar as texturas? Pode haver mais espaço disponível do que você imaginava. Você deve criar recursos e verificar se há erros "sem memória" e, em seguida, reduzir as texturas. Por exemplo, você pode remover os níveis mip superiores de suas texturas.
Qual é um bom padrão de uso para buffers de vértices se eu estiver gerando dados dinâmicos?
- Crie um buffer de vértice usando os sinalizadores de uso D3DUSAGE_DYNAMIC e D3DUSAGE_WRITEONLY e o sinalizador de pool D3DPOOL_DEFAULT. (Especifique também D3DUSAGE_SOFTWAREPROCESSING se você estiver usando processamento de vértice de software.)
- I = 0.
- Defina o estado (texturas, estado de renderização e assim por diante).
- Verifique se há espaço no buffer, ou seja, por exemplo, I + M <= N? (Em que M é o número de novos vértices).
- Se sim, então bloqueie o VB com D3DLOCK_NOOVERWRITE. Isso informa ao Direct3D e ao driver que você adicionará vértices e não modificará os que você colocou em lote anteriormente. Portanto, se uma operação DMA estava em andamento, ela não é interrompida. Se não, goto 11.
- Preencha os vértices M em I.
- Desbloqueie.
- Chame Draw[Indexed]Primitive. Para primitivos não indexados, use I como o parâmetro StartVertex. Para primitivos indexados, verifique se os índices apontam para a parte correta do buffer de vértice (pode ser mais fácil usar o parâmetro BaseVertexIndex da chamada SetIndices para conseguir isso).
- I += M.
- Goto 3.
- Estamos sem espaço, então vamos começar com um novo VB. Não queremos usar o mesmo porque pode haver uma operação DMA em andamento. Nós comunicamos isso ao Direct3D e ao driver bloqueando o mesmo VB com o sinalizador D3DLOCK_DISCARD. Isso significa que "você pode me dar um novo ponteiro porque já não uso o antigo e realmente não me importo mais com o conteúdo antigo".
- I = 0.
- Goto 4 (ou 6).
Por que tenho que especificar mais informações na estrutura D3DVERTEXELEMENT9?
A partir do Direct3D 9, a declaração de fluxo de vértice não é mais apenas uma matriz dword, agora é uma matriz de estruturas D3DVERTEXELEMENT9. O tempo de execução faz uso das informações semânticas e de uso adicionais para vincular o conteúdo de fluxos de vértice a registradores/variáveis de entrada de sombreadores de vértice. Para o Direct3D 9, as declarações de vértice são desacopladas dos sombreadores de vértice, o que facilita o uso de sombreadores com geometrias de diferentes formatos, pois o tempo de execução vincula apenas os dados necessários para o sombreador.
As novas declarações de vértice podem ser usadas com o pipeline de função fixa ou com sombreadores. Para o pipeline de função fixa, não há necessidade de chamar SetVertexShader. Se, no entanto, você quiser alternar para o pipeline de função fixa e tiver usado anteriormente um sombreador de vértice, chame SetVertexShader(NULL). Quando isso for feito, você ainda precisará chamar SetFVF para declarar o código FVF.
Ao usar sombreadores de vértice, chame SetVertexShader com o objeto de sombreador de vértice. Além disso, chame SetFVF para configurar uma declaração de vértice. Isso usa as informações implícitas no FVF. SetVertexDeclaration pode ser chamado no lugar de SetFVF porque oferece suporte a declarações de vértice que não podem ser expressas com um FVF.
Biblioteca de utilitários D3DX
Quais formatos de arquivo são suportados pelas funções do carregador de arquivos de imagem D3DX?
As funções do carregador de arquivos de imagem D3DX suportam arquivos BMP, TGA, JPG, DIB, PPM e DDS.
As funções de renderização de texto no D3DX parecem não estar funcionando. O que estou fazendo de errado?
Um erro comum ao usar as funções ID3DXFont::DrawText é especificar um componente alfa zero para o parâmetro de cor, resultando em texto completamente transparente (ou seja, invisível). Para texto totalmente opaco, verifique se o componente alfa do parâmetro de cor está totalmente saturado (255).
Como posso salvar o conteúdo de uma superfície ou textura em um arquivo?
O SDK do DirectX 8.1 adicionou duas funções à biblioteca D3DX especificamente para essa finalidade: D3DXSaveSurfaceToFile() e D3DXSaveTextureToFile(). Essas funções suportam salvar uma imagem em arquivo no formato BMP ou DDS. Nas versões anteriores, você terá que bloquear a superfície e ler os dados da imagem e, em seguida, gravá-los em um arquivo bitmap. Para obter informações sobre como escrever uma função para armazenar bitmaps, consulte Armazenar uma imagem.
Como alternativa, o GDI+ pode ser usado para salvar a imagem em uma ampla variedade de formatos, embora isso exija arquivos de suporte adicionais a serem distribuídos com seu aplicativo.
Como posso usar o HLSL (High Level Shader Language) no meu jogo?
Há três maneiras pelas quais o HLSL (High Level Shader Language) da Microsoft pode ser incorporado ao seu mecanismo de jogo:
- Compile a origem do sombreador em um assembly de sombreamento de vértice ou de pixel (usando o utilitário de linha de comando fxc.exe) e use D3DXAssembleShader() no tempo de execução. Dessa forma, até mesmo um jogo DirectX 8 pode até aproveitar o poder do HLSL.
- Use D3DXCompileShader() para compilar sua fonte de sombreador no fluxo de token e na forma de tabela constante. No tempo de execução, carregue o fluxo de token e a tabela constante e chame CreateVertexShader() ou CreatePixelShader() no dispositivo para criar seus sombreadores.
- A maneira mais fácil de colocar em funcionamento é aproveitar o sistema D3DX Effects chamando D3DXCreateEffectFromFile() ou D3DXCreateEffectFromResource() com seu arquivo de efeito.
Qual é o objetivo do novo sinalizador de compilador do sombreador?
A partir do SDK do DirectX de dezembro de 2006, o novo compilador HLSL desenvolvido para Direct3D 10 foi habilitado para destinos Direct3D 9. O novo compilador não tem suporte para destinos ps_1_x e agora é o compilador padrão para todos os sombreadores HLSL do Direct3D. Um sinalizador para compatibilidade com versões anteriores pode ser usado para forçar destinos ps_1_x a compilar como destinos ps_2_0.
Os aplicativos que desejam usar o compilador herdado podem continuar a fazê-lo fornecendo um sinalizador no tempo de execução (consulte sinalizadores de compilador) ou fornecendo uma alternância ao usar fxc.
Qual é a maneira correta de obter sombreadores de um efeito?
Use D3DXCreateEffect para criar um ID3DXEffect e, em seguida, use GetPassDesc para recuperar um D3DXPASS_DESC. Essa estrutura contém ponteiros para sombreadores de vértice e de pixel.
Não use ID3DXEffectCompiler::GetPassDesc. Os identificadores de sombreador de vértice e de pixel retornados desse método são NULL.
Para que serve o HLSL noise() intrinsic?
A função intrínseca do ruído gera o ruído de Perlin como definido por Ken Perlin. Atualmente, a função HLSL só pode ser usada para preencher texturas em sombreadores de textura, pois o h/w atual não oferece suporte ao método nativamente. Os sombreadores de textura são usados em conjunto com as funções D3DXFill*Texture(), que são funções auxiliares úteis para gerar texturas definidas processualmente durante o tempo de carregamento.
Como fazer para detectar se devo usar o modelo de sombreador de pixel 2.0 ou 2.a?
Você pode usar as funções D3DXGetPixelShaderProfile() e D3DXGetPixelShaderProfile() que retornam uma cadeia de caracteres determinando qual perfil HLSL é mais adequado para o dispositivo que está sendo executado.
Como fazer para acessar os parâmetros em meus Sombreadores de efeitos pré-compilados?
Através da interface ID3DXConstantTable que é usada para acessar a tabela constante. Essa tabela contém as variáveis que são usadas por sombreadores e efeitos de linguagem de alto nível.
Existe uma maneira de adicionar dados do usuário a um efeito ou a outro recurso?
Sim, para definir dados privados você chama SetPrivateData (pReal é o objeto de textura D3D, pSpoof é o objeto de textura encapsulado).
hr = pReal->SetPrivateData(IID_Spoof, &pSpoof,
sizeof(IDirect3DResource9*), 0)));
Para procurar o ponteiro encapsulado:
IDirect3DResource9* pSpoof;
DWORD dwSize = sizeof(pSpoof);
hr = pReal->GetPrivateData(IID_Spoof, (void*) &pSpoof, &dwSize);
Por que a renderização de um objeto ID3DXMesh diminui significativamente depois que eu defino subconjuntos?
Você provavelmente não otimizou a malha depois de definir os atributos da face. Se você especificar atributos e, em seguida, chamar ID3DXMesh::DrawSubset(), esse método deve executar uma pesquisa de malha para todas as faces que contêm os atributos solicitados. Além disso, as faces renderizadas provavelmente estão em um padrão de acesso aleatório, não utilizando cache de vértices. Depois de definir os atributos de face para seus subconjuntos, chame os métodos ID3DXMesh::Optimize ou ID3DXMesh::OptimizeInPlace e especifique um método de otimização D3DXMESHOPT_ATTRSORT ou mais forte. Observe que, para um desempenho ideal, você deve otimizar com o sinalizador D3DXMESHOPT_VERTEXCACHE, que também reordenará vértices para uma utilização ideal do cache de vértices. A matriz de adjacência gerada para uma Malha D3DX tem três entradas por face, mas algumas faces podem não ter faces adjacentes em todas as três bordas. Como isso é codificado? As entradas nas quais não há faces adjacentes são codificadas como 0xffffffff.
Já ouvi falar muito sobre a PRT (Transferência de Radiância Pré-computada), onde posso saber mais?
O PRT é um novo recurso do D3DX adicionado na atualização do SDK do verão de 2003. Ele permite a renderização de cenários complexos de iluminação, como iluminação global, sombreamento suave e dispersão de subsuperfície em tempo real. O SDK contém documentação e exemplos de como integrar a tecnologia ao seu jogo. Os exemplos PRT Demo Sample e LocalDeformablePRT Sample demonstram como usar o simulador em cenários de iluminação por vértice e por pixel, respectivamente. Mais informações sobre isso e outros tópicos também podem ser encontradas na página do Peter Pike Sloan.
Como posso renderizar em uma textura e fazer uso do Anti-Aliasing?
Crie um destino de renderização com várias amostras usando Direct3DDevice9::CreateRenderTarget. Depois de renderizar a cena para esse destino de renderização, faça StretchRect a partir dela para uma textura de destino de renderização. Se você fizer alguma alteração na textura fora da tela (como desfoca-lo ou torna-lo incandescente), copie-o de volta para o buffer de fundo antes de present().
Perguntas sobre o DirectSound
Por que recebo uma explosão de estática quando meu aplicativo é iniciado? Percebo esse problema com outros aplicativos também.
Você provavelmente instalou a depuração do tempo de execução do DirectX. A versão de depuração do tempo de execução preenche buffers com estática para ajudar os desenvolvedores a detectar bugs com buffers não inicializados. Você não pode garantir o conteúdo de um buffer do DirectSound após a criação. Em especial, você não pode supor que um buffer será zerado.
Por que estou enfrentando um atraso entre alterar um parâmetro de efeitos e ouvir os resultados?
As alterações nos parâmetros de efeito nem sempre ocorrem imediatamente no DirectX 8. Para eficiência, o DirectSound processa 100 milissegundos de dados de som em um buffer, começando no cursor de reprodução, antes que o buffer seja reproduzido. Esse pré-processamento acontece após todas as seguintes chamadas:
IDirectSoundBuffer8::SetCurrentPosition
IDirectSoundBuffer8::SetFX
IDirectSoundBuffer8::Stop
IDirectSoundBuffer8::Unlock
A partir do DirectX 9, um novo algoritmo de processamento FX que processa efeitos just-in-time resolve esse problema e reduziu a latência. O algoritmo foi adicionado à chamada IDirectSoundBuffer8::Play(), juntamente com um thread adicional que processa efeitos logo à frente do cursor de gravação. Assim, você pode definir parâmetros a qualquer momento e eles funcionarão conforme o esperado. No entanto, observe que em um buffer de reprodução haverá um pequeno atraso (geralmente 100 ms) antes de ouvir a alteração de parâmetro, porque o áudio entre os cursores de reprodução e gravação (e um pouco mais de preenchimento) já foi processado naquele momento.
Como posso detectar se o DSound está instalado?
Se você não precisar usar DirectSoundEnumerate() para listar os dispositivos DSound disponíveis, não vincule seu aplicativo a dsound.lib e, em vez disso, use-o através COMs CoCreateInstance(CLSID_DirectSound...) e inicialize o objeto DSound usando Initialize(NULL). Se você precisar usar DirectSoundEnumerate(), poderá carregar dsound.dll dinamicamente usando LoadLibrary("dsound.dll"); e acessar seus métodos usando GetProcAddress("DirectSoundEnumerateA/W") e GetProcAddress("DirectSoundCreateA/W") e assim por diante.
Como fazer para criar áudio multicanal com WAVEFORMATEXTENSIBLE?
Se você não conseguir encontrar uma resposta para sua pergunta nos arquivos de ajuda do DirectSound, há um ótimo artigo com mais informações disponíveis em Dados de áudio de vários canais e Arquivos WAVE.
Como posso usar o Gerenciador de Voz do DirectSound com conjuntos de propriedades como EAX?
No DirectSound 9.0, quando você duplica um buffer, agora é possível obter a interface IDirectSoundBuffer8 no buffer duplicado, o que lhe dará acesso ao método AcquireResources. Isso permitirá que você associe um buffer ao sinalizador DSBCAPS_LOCDEFER a um recurso de hardware. Em seguida, você pode definir seus parâmetros EAX nesse buffer antes de ter que chamar Play().
Estou tendo problemas com comportamento não confiável ao usar notificações de posição do cursor. Como posso obter informações mais precisas?
Existem alguns bugs sutis em várias versões do DirectSound, a pilha de áudio principal do Windows e drivers de áudio que tornam as notificações de posições do cursor não confiáveis. A menos que você esteja direcionando uma configuração HW/SW conhecida na qual você sabe que as notificações são bem comportadas, evite notificações de posição do cursor. Para o controle de posição, GetCurrentPosition() é uma técnica mais segura.
Está ocorrendo degradação do desempenho quando eu uso GetCurrentPosition(). O que posso fazer para melhorar o desempenho?
Cada chamada GetCurrentPosition() em cada buffer causa uma chamada do sistema, e as chamadas do sistema devem ser minimizadas, pois são um grande componente do espaço ocupado pela CPU do DSound. No NT (Win2K e XP), os cursores em buffers SW (e buffers HW em alguns dispositivos) se movem em incrementos de 10 ms, então chamar GetCurrentPosition() a cada 10 ms é ideal. Chamá-lo com mais frequência do que a cada 5 ms causará uma degradação do desempenho.
Meu aplicativo DirectSound está ocupando muito tempo de CPU ou está executando lentamente. Posso fazer alguma coisa para otimizar meu código?
Há várias coisas que você pode fazer para melhorar o desempenho do seu código de áudio:
Não chame GetCurrentPosition com muita frequência. Cada chamada GetCurrentPosition() em cada buffer causa uma chamada do sistema, e as chamadas do sistema devem ser minimizadas, pois são um grande componente do espaço ocupado pela CPU do DSound. No NT (Win2K e XP), os cursores em buffers SW (e buffers HW em alguns dispositivos) se movem em incrementos de 10 ms, então chamar GetCurrentPosition() a cada 10 ms é ideal. Chamá-lo com mais frequência do que a cada 5 ms causará uma degradação do desempenho.
Utilize uma taxa de quadros separada e mais baixa para o áudio. Hoje em dia muitos jogos do Windows podem exceder 100 quadros por segundo e não é necessário, na maioria dos casos, atualizar seus parâmetros de áudio 3D na mesma taxa de quadros. Processar seu áudio a cada segundo ou terceiro quadro gráfico, ou a cada 30 ms ou mais, pode reduzir significativamente o número de chamadas de áudio em todo o aplicativo sem reduzir a qualidade do áudio.
Use DS3D_DEFERRED para objetos 3D. A maioria das placas de áudio responde imediatamente a mudanças de parâmetros e em um único quadro muita coisa pode mudar, principalmente se você mudar a posição ou a orientação do ouvinte. Isso faz com que a placa de áudio/CPU realize muitos cálculos desnecessários, então outra otimização rápida e universal é adiar algumas alterações de parâmetros e confirmá-las no final do quadro.
ou pelo menos use SetAllParameters em vez de chamadas individuais Set3DParamX em buffers.
Da mesma forma, você deve usar pelo menos chamadas SetAllParamenters em buffers 3D em vez de chamadas individuais Set3DParamX. Apenas tente minimizar as chamadas do sistema sempre que possível.
Não faça chamadas redundantes. Armazene e classifique uma lista de chamadas de reprodução. Muitas vezes, em um quadro de atualização de áudio, há 2 solicitações para reproduzir novos sons. Se as solicitações forem processadas à medida que chegam, o primeiro novo som poderá ser iniciado e, em seguida, imediatamente substituído o segundo som solicitado. Isso resulta em cálculos redundantes, uma chamada de reprodução desnecessária e uma chamada de interrupção desnecessária. É melhor armazenar uma lista de pedidos para que novos sons sejam reproduzidos, para que a lista possa ser classificada, e apenas as vozes que devem começar a tocar, sejam realmente tocadas.
Além disso, você deve armazenar cópias locais dos parâmetros 3D e EAX para cada fonte de som. Se uma solicitação for feita para definir um parâmetro para um valor específico, você poderá verificar se o valor é realmente diferente do último conjunto de valores. Se não for, a ligação não precisa ser feita.
Embora o driver da placa de áudio provavelmente detectará esse cenário e não executará o (mesmo) cálculo novamente, a chamada de áudio terá que chegar ao driver de áudio (através de uma transição de toque) e isso já é uma operação lenta.
Quando eu transmito um buffer, ele tende a falhar e ter um desempenho ruim. Qual é a melhor maneira de transmitir um buffer?
Ao transmitir áudio em um buffer, há dois algoritmos básicos: AWC (After-Write-Cursor) e BPC (Before-Play-Cursor). O AWC minimiza a latência ao custo de falha, enquanto o BPC é o oposto. Como geralmente não há alterações interativas no som transmitido, esse tipo de latência raramente é um problema para jogos e aplicativos semelhantes, então o BPC é o algoritmo mais apropriado. No AWC, toda vez que o thread de streaming é executado, você "repõe" os dados em seus buffers de loop até N ms além de seus cursores de gravação (normalmente N = 40 ou mais, para permitir a oscilação de escalonamento do Windows). No BPC, você sempre grava o máximo de dados possível nos buffers, preenchendo-os diretamente em seus cursores de reprodução (ou talvez 32 bytes antes para permitir que os drivers informem incorretamente o progresso do cursor de reprodução).
Use BPC para minimizar falhas e use buffers de 100 ms ou mais, mesmo que seus jogos não falhem em seu hardware de teste, ele falhará em algum computador.
Estou executando os mesmos sons várias vezes e muito rapidamente e, às vezes, eles não são reproduzidos, ou a chamada Play() demora muito tempo. O que devo fazer?
A latência de inicialização (que é diferente da latência de streaming mencionada acima) pode ser um problema no caso de algum hardware (a chamada Play() leva muito tempo, às vezes, em determinadas placas de áudio). Se você realmente quiser reduzir essa latência, para efeitos sonoros (tiros, passos e assim por diante) um truque útil é manter alguns buffers sempre em loop e tocando silêncio. Quando você precisar reproduzir um efeito sonoro, escolha um buffer livre, veja onde está o cursor de gravação e coloque o som no buffer logo após o cursor de gravação. Algumas placas de áudio falham no QuerySupport em propriedades adiadas que eu sei que elas suportam. Há uma solução alternativa? Você pode simplesmente realizar QuerySupport em versões não adiadas das propriedades e usar configurações adiadas de qualquer maneira. Os drivers de placa de áudio mais recentes também podem corrigir esse problema.
Como fazer para codificar arquivos WAV em WMA?
Consulte a documentação sobre o Codificador do Windows Media em: Codificador do Windows Media 9 Series.
Como decodificar arquivos MP3 com o DirectSound?
O DirectSound não suporta nativamente a decodificação MP3. Você mesmo pode decodificar os arquivos com antecedência (usando um codec ACM de um filtro DirectShow), ou então usar o próprio DirectShow, que pode fazer a decodificação por você. Em seguida, você pode copiar os dados de áudio PCM resultantes para seus buffers DirectSound.
DirectX Extensions para Alias Maya
Por que meu NURBS não está aparecendo?
Não há suporte para NURBS. Você pode convertê-los em malhas poligonais.
Por que meus SUBDs não estão aparecendo?
Não há suporte para SUBDs. Você pode convertê-los em malhas poligonais.
Por que minha animação no arquivo X parece diferente da animação na janela de visualização?
A janela de visualização não está animando no sentido mais estrito da questão. Ela não está reproduzindo animação, mas sim sincronizando com o estado mais atual da cena do Maya. Quando a animação é exportada, as matrizes em cada transformação são decompostas em escala, rotação (quatérnions) e componentes de conversão (muitas vezes referidos como SRTs). Os SRTs são mais desejáveis do que as matrizes porque interpolam bem, fornecem uma forma mais compacta dos dados e podem ser compactados independentemente. Nem todas as matrizes podem ser divididas em SRTs. Se eles não puderem se decompor, os SRTs resultantes serão desconhecidos, portanto, pequenos erros na animação podem ser detectados. As duas características no Maya que mais causam problemas durante a decomposição são distorções e rotações ou escalas fora do centro. Se estiver ocorrendo esse problema, porque você está usando rotações ou escalas fora do centro, considere adicionar transformações adicionais aumentando seu nível de hierarquia.
Onde a animação D3DX suporta SRTs, ela tem a seguinte aparência:
[S]x[R]x[T]
As matrizes do Maya são muito mais complicadas e exigem uma quantidade significativa de processo adicional, que se parece com isso:
[SpInv]x[S]x[Sh]x[Sp]x[St]x[RpInv]x[Ro]x[R]x[Rp]x[Rt]x[T]
Eu apliquei uma capa na minha malha com RigidSkin, mas a malha (ou parte) não está se movendo. Por quê?
O Rigid Skin do Maya não é suportado no momento. Use o Smooth Skin.
Para onde foi todo o meu IK no arquivo X?
Os arquivos X não suportam IK. Em vez disso, as soluções IK são incorporadas nos quadros armazenados no arquivo X.
Por que nenhuma das cores dos meus materiais aparece, exceto DirectXShaders?
O DirectX Extensions para Maya atualmente oferece suporte apenas a materiais DirectXShader para visualização e exportação. Em uma versão futura, outros materiais podem ser suportados.
Perguntas sobre o XInput
Posso usar o DirectInput para ler os gatilhos?
Sim, mas funcionam como o mesmo eixo. Portanto, você não pode ler os gatilhos independentemente com o DirectInput. Usando o XInput, os gatilhos retornam valores separados.
Para obter mais informações sobre por que o DirectInput interpreta os gatilhos como um eixo, consulte Usar um controlador com DirectInput.
Quantos controladores o XInput suporta?
O XInput suporta 4 controladores conectados ao mesmo tempo.
O XInput dá suporte a controladores não comuns?
Não, ele não dá suporte.
Os controladores comuns estão disponíveis por meio do DirectInput?
Sim, você pode acessar controladores comuns por meio do DirectInput.
Como fazer para forçar feedback sobre os controladores comuns?
Use a função XInputSetState.
Por que meu dispositivo de áudio padrão muda?
Ao conectar o fone de ouvido, o fone de ouvido do controlador atua como um dispositivo de áudio USB padrão, portanto, quando ele é conectado, o Windows muda automaticamente para usar esse dispositivo de áudio USB como padrão. Como o usuário provavelmente não quer que todo o áudio passe pelo fone de ouvido, ele precisará ajustá-lo manualmente de volta à configuração original.
Como fazer para controlar as luzes do controlador?
As luzes do controlador são predeterminadas pelo sistema operacional e não podem ser alteradas.
Como fazer para acessar o botão do Xbox 360 em meus aplicativos?
Desculpe, esse botão está reservado para uso futuro.
Onde posso obter os drivers?
Os drivers estarão disponíveis através do Windows Update.
Como a ID do controlador é determinada?
Na inicialização do XInput, a ID é determinada de forma não determinística pelo mecanismo XInput e pelos controladores conectados. Se os controladores estiverem conectados enquanto um aplicativo XInput estiver em execução, o sistema atribuirá ao novo controlador o menor número disponível. Se um controlador for desconectado, seu número será disponibilizado novamente.
Como fazer para obter os dispositivos de áudio para o controlador?
Use a função XInputGetDSoundAudioDeviceGuids. Consulte o exemplo do AudioController para obter detalhes.
O que devo fazer quando um controlador é desconectado?
Se o controle estava em uso por um jogador, você deve pausar o jogo até que o controle seja reconectado e o jogador pressione um botão para sinalizar que está pronto para reproduzir.