Eu entendo a sintaxe do HLSL, por exemplo, vamos fingir que tenho isso como meu HLSL:
struct VOut
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
VOut VShader(float4 position : POSITION, float4 color : COLOR)
{
VOut output;
output.position = position;
output.position.xy *= 0.7f; // "shrink" the vertex on the x and y axes
output.color = color;
return output;
}
float4 PShader(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
return color;
}
e eu compilo assim:
D3DX11CompileFromFile(L"shaders.hlsl", 0, 0, "VShader", "vs_5_0", 0, 0, 0, &VS, 0, 0);
D3DX11CompileFromFile(L"shaders.hlsl", 0, 0, "PShader", "ps_5_0", 0, 0, 0, &PS, 0, 0);
Como é que isso ... sabe mudar ... Estou confuso sobre exatamente qual é o pipeline entre HLSL e os pixels / vértices reais na tela.
É isso que realmente os "aplica"?
dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);
// set the shader objects
devcon->VSSetShader(pVS, 0, 0);
devcon->PSSetShader(pPS, 0, 0);
Tenha em mente que sou um iniciante literal nessas coisas. Alguém pode explicar o que está fazendo? Estou assumindo que a função HLSL do vértice passa por todos os vértices e os altera para o que eu tenho na função, e a saída é o que foi alterado ... e da mesma forma para o pixel shader?
Outra confusão, eu sei o que é um pixel e entendo o que é um vértice ... mas o que exatamente o shader de pixel faz?
Respostas:
Funciona aproximadamente da seguinte maneira: quando você executa uma chamada de desenho (DrawPrimitives, DrawIndexedPrimitives em D3D, Draw em 10+, etc.), os dados de geometria que você vinculou ao pipeline (seus buffers de vértices) são processados. Para cada vértice, o sombreador de vértice é executado para produzir um vértice de saída no espaço do clipe.
A GPU executa algumas funções fixas no vértice do espaço do clipe, como recortar / separar e colocar o vértice no espaço da tela, onde começa a rasterizar os triângulos. Durante a rasterização de cada triângulo, a GPU interpola atributos de vértices na superfície desse triângulo, alimentando cada atributo interpolado ao sombreador de pixels para produzir uma cor semifinal para esse pixel (a mistura é aplicada depois que o sombreador é executado, portanto, "semi- final").
O código que você postou primeiro compila os sombreadores e os vincula ao pipeline, onde eles permanecem ativos para todas as chamadas de desenho subsequentes até serem alteradas. Na verdade, não faz com que sejam executados.
O sombreador de vértice é responsável por transformar os vértices do espaço do modelo para o espaço do clipe.
O pixel shader é responsável por calcular a penúltima cor / profundidade de um pixel com base em atributos de vértices interpolados.
fonte
Vou tentar explicar como as coisas funcionam sem usar muito jargão.
Se a sua preocupação é a simplicidade, e não a velocidade interativa, uma superfície 3D no computador seria apenas uma enorme nuvem de pontos no espaço, suficientemente densa para que possamos renderizar cada ponto individualmente, sem espaços entre eles.
Você deseja armazenar um modelo apenas uma vez na memória, mas precisa exibi-lo em vários tamanhos e ângulos; portanto, ao renderizar um modelo 3D, é necessário "transformar" todos os pontos à medida que os lê da memória. Por exemplo, para tornar o modelo 50% maior, é necessário escalar as posições dos pontos pela metade:
Este é quase o "shader de vértice" mais simples que se pode conceber: entra uma posição de vértice da memória e sai uma nova posição de vértice, com a metade do tamanho. O vértice da metade do tamanho não é armazenado na memória - é usado imediatamente para renderização e depois jogado fora.
Embora seja uma simplificação grosseira que carece de conceitos-chave , isso em espírito descreve aspectos de como os filmes fazem gráficos.
Os gráficos interativos (jogos) não podem ser tão simples, porque precisam renderizar gráficos com várias ordens de magnitude mais rapidamente do que um filme.
Nos jogos, não podemos dar ao luxo de render um ponto para cada pixel na tela, além de extras para cobrir as lacunas. Portanto, como um compromisso, o espaço entre cada três pontos próximos é renderizado como um triângulo, que por várias razões técnicas prefere ter pelo menos 10 pixels de tamanho na tela.
Um triângulo 3D pode ser projetado em uma tela 2D e depois dividido em uma pilha de linhas 1D, que podem ser divididas em uma pilha de pixels 0D. Assim, podemos dividir e conquistar o problema de renderizar um triângulo 3D no problema mais simples de renderizar muitos pixels 0D isoladamente. Um computador pode resolver problemas mais simples em menos tempo.
Um pixel shader é um pequeno programa que executamos em cada pixel gerado pela desmontagem de um triângulo.
Este é quase o "pixel shader" mais simples que se pode conceber: entra uma mistura das cores de três vértices triangulares e sai a mesma cor. As entradas são provenientes das saídas do "vertex shader" e as saídas são gravadas na tela na memória.
Então - o "vertex shader" é um programa que roda dentro do chip da GPU. Sua entrada é um "buffer de vértice" na memória da GPU e sua saída é alimentada diretamente em um "pixel shader". Um "pixel shader" também é um programa executado dentro do chip da GPU. Suas entradas são uma mistura de três vértices do sombreador de vértices e sua saída é um pixel na tela.
fonte
Além das outras respostas, aqui está uma pequena imagem do que acontece
Desde os estágios do pipeline, d3d10 (o mesmo que d3d11).
Veja também
fonte
Não se preocupe com um pixel shader no momento. Se você é um novato completo, deve ser o olá mundo do GLSL / HLSL apenas com sombreadores de vértices e fragmentos. Quando você estiver familiarizado e começar a entender movimentos variáveis e outros, expanda seus horizontes.
Eu recomendo um livro de texto para obter detalhes sobre como a API funciona. Os livros do OpenGL também fazem um bom trabalho, ilustrando como as coisas mudaram ao longo dos anos, do pipeline fixo ao pipeline dinâmico programável.
Vá campeão!
fonte