Link

Matrizes MVP e uniform buffer

Quando preparamos uma geometria que será desenhada em um aplicativo 3D, a geometria geralmente é modelada no sistema de coordenadas local – aquele em que é mais conveniente para o artista criar o modelo. No entanto, o pipeline gráfico espera que os vértices sejam transformados em um espaço de recorte (ou projetivo), pois é mais fácil (e mais rápido) executar muitas operações nesse sistema de coordenadas. Geralmente é o vertex shader que realiza essa transformação. Para isso, precisamos preparar uma matriz que represente uma perspectiva ou projeção ortogonal. A transformação do espaço local para o espaço de recorte é realizada apenas multiplicando a matriz pela posição de um vértice.

Além da matriz de projeção, temos as matrizes de visão e modelo. A matriz de visão tem a função de transformar o espaço do modelo para o espaço da câmera. A matriz de modelo transforma o espaço coordenado local de um objeto para o espaço do mundo.

Se compusermos todas as três, podemos usar o resultado para mapear todo o espaço de objetos para o espaço de tela, fazendo com que consigamos descobrir o que precisa passar para o próximo estágio do pipeline gráfico a partir das posições dos vértices de entrada. O conjunto dessas matrizes nós damos o nome de matrizes MVP e as transformações realizadas por elas, de transformações MVP.

Poderíamos incluir essas matrizes como dados de vértice, mas isso seria um desperdício de memória e exigiria que atualizássemos o buffer de vértice sempre que as transformações fossem alteradas. As transformações poderiam facilmente mudar em praticamente todos os quadros.

Uma das formas de resolver isso no Vulkan é usar objetos de uniform1 buffer (UBO, do inglês uniform buffer object). Um uniform buffer é um buffer que é acessível somente para leitura pelos shaders, para que os shaders possam ler dados constantes dos parâmetros.

1 Uma variável uniform é uma variável global do shader declarada com o qualificador uniform. Variáveis uniform atuam como parâmetros que o usuário de um programa shader pode transmitir para esse programa. Variáveis uniform têm esse nome porque não mudam de uma chamada de shader para a seguinte em uma chamada de renderização específica. Isso as diferencia das entradas e saídas do estágio de shader, que geralmente são diferentes para cada chamada de um estágio de shader (KHRONOS, 2019b).

Digamos que temos os dados que queremos e que são armazenados em nosso aplicativo em uma estrutura como esta:

struct UniformBufferObject {
	QMatrix4x4 model;
	QMatrix4x4 view;
	QMatrix4x4 proj;
};

Então, podemos copiar esses dados para um VkBuffer e acessá-los através de um descritor de UBO a partir do vertex shader, assim:

layout(set = 0, binding = 1) uniform UniformBufferObject {
	mat4 model;
	mat4 view;
	mat4 proj;
} ubo;

void main() {
	gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
	fragColor = inColor;
	fragTexCoord = inTexCoord;
}

O primeiro passo é definir o UBO no código C++. Vamos criar uma nova estrutura em renderer.h chamada UniformBufferObject:

struct UniformBufferObject {
	QMatrix4x4 model;
	QMatrix4x4 view;
	QMatrix4x4 proj;
};

Atualizando o vertex shader

O próximo passo é modificar o vertex shader para incluir o UBO como foi especificado acima. Assumiremos que o leitor esteja familiarizado com as transformações MVP.

layout(set = 0, binding = 1) uniform UniformBufferObject {
	mat4 model;
	mat4 view;
	mat4 proj;
} ubo;

layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec2 inTexCoord;

layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragTexCoord;

void main() {
	gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
	fragColor = inColor;
	fragTexCoord = inTexCoord;
}

A linha que calcula gl_Position é alterada para que agora o vertex shader leve em conta a matriz MVP. O último componente do vetor não será mais 0, pois divide as outras coordenadas com base na distância da câmera para criar um efeito de profundidade.


Anterior Próximo