Estou procurando uma maneira elegante de lidar com layouts de entrada no meu código directx11.
O problema que tenho é que tenho uma classe Effect e uma classe Element. A classe de efeito encapsula shaders e configurações semelhantes, e a classe Element contém algo que pode ser desenhado (modelo 3d, paisagem etc.)
Meu código de desenho define os shaders do dispositivo, etc., usando o efeito especificado e, em seguida, chama a função de desenho do elemento para desenhar a geometria real contida nele.
O problema é este - eu preciso criar um D3D11InputLayout em algum lugar. Isso realmente pertence à classe Element, pois não é da conta do resto do sistema como esse elemento escolhe representar seu layout de vértice. Mas, para criar o objeto, a API requer o bytecode do shader de vértice para o shader de vértice que será usado para desenhar o objeto. No directx9, era fácil, não havia dependência, portanto meu elemento poderia conter suas próprias estruturas de layout de entrada e defini-las sem o efeito estar envolvido.
Mas o elemento realmente não precisa saber nada sobre o efeito com o qual está sendo desenhado, isso é apenas as configurações de renderização e o elemento existe para fornecer geometria.
Então, eu realmente não sei onde armazenar e como selecionar o InputLayout para cada chamada de empate. Quero dizer, fiz algo funcionar, mas parece muito feio.
Isso me faz pensar que perdi algo óbvio, ou então o meu design de ter todas as configurações de renderização em um Efeito, a Geometria em um Elemento e um terceiro que desenha tudo é apenas falho.
Imaginando como mais alguém lida com seus layouts de entrada no directx11 de maneira elegante?
Obrigado pelas respostas, elas são muito úteis. Vou adicionar uma resposta à minha própria pergunta, porque segui em frente um pouco.
No final, percebi que talvez querer separar completamente os shaders dos itens desenháveis fosse um erro. Eles são fundamentalmente acoplados na "vida real", por isso talvez não seja um problema que eles estejam no design.
Por exemplo, um sombreador de água funcionará apenas com um elemento que deseja extrair água. Somente isso poderá fornecer os dados necessários. Um sombreador que desenha modelos animados funcionará apenas com um elemento de modelo animado. De repente, não consigo decidir usar um shader de água com um modelo animado. Simplesmente não pode funcionar.
Tentar criar uma classe abstrata de sombreador que possa carregar qualquer sombreador e trabalhar com qualquer elemento extraível é um erro. Não reflete como eles podem ser usados na realidade.
Então, em vez disso, criei classes de sombreador AnimatedModelShader, WaterShader, LandscapeShader. Cada um deles pode ter opções que fazem com que ele carregue diferentes arquivos de sombreador físico, mas eles sempre terão a mesma interface básica por necessidade, porque um sombreador de paisagem sempre precisará do mesmo tipo de entrada de dados.
Portanto, o shader agora é responsável por criar seu próprio layout de entrada e informa ao elemento que o usa como fazer o layout de seus vértices, tendo um typedef público chamado vertexType que o elemento usa se desejar usar esse shader.
Nem um pouco do meu design original, mas, como se vê, o desejo de separar os dois conceitos não era muito útil.
fonte
Faço algo semelhante ao dotminic - tenho uma rotina para a qual passo uma matriz de D3D11_INPUT_ELEMENT_DESC, que constrói um shader de vértice falso com uma assinatura de entrada correspondente, o compila e cria um layout a partir dele, finalmente liberando o shader falso.
Sim, é feio, e sim, significa precisar ser um pouco mais cuidadoso do que eu faria se fizesse da maneira correta, mas são trocas que estou preparada para aceitar em troca de uma separação mais limpa.
fonte
Parece-me que você realmente não deveria se preocupar. Depois de olhar através da documentação do MSDN para CreateInputLayout, me deparei com isso:
http://msdn.microsoft.com/en-gb/library/windows/desktop/ff476512(v=vs.85).aspx
Isso deixa bem claro que você deve poder tratar seus layouts de entrada quase exatamente da mesma maneira que suas antigas declarações de vértice do DX9. O fornecimento de bytecode do shader na primeira vez que você cria cada um deles permite que o DX11 os valide. E, aparentemente, o pior que acontecerá se você evitar ou falhar nesta etapa é um aviso de tempo de execução que parece seguro ignorar.
Portanto, o DX11 não está "criando uma dependência" entre seus layouts de entrada e seus shaders ... está oferecendo validação gratuita! : D
fonte
CreateInputLayout
também pode ser usado para validar um sombreador em relação a um layout de entrada existente, para que você possa verificar todos os sombreadores que o usariam - o que eu recomendaria fazer, pelo menos em compilações de depuração, por segurança.D3D11_INPUT_ELEMENT_DESC
s usada para criá-lo. Isso pode ser validado no bytecode de outro shader sem criar um novo objeto de layout de entrada.