본문 바로가기

Vulkan

Vertex input description

이전 글 : Swap chain recreation

다음 글 : Vertex buffer creation



Vertex input description
정점 입력 설명

Introduction


다음 몇 장에서는 버텍스 쉐이더자체에 하드 코드 된 버텍스 데이터를 메모리의 버텍스 버퍼로 대체 할 것입니다. CPU 가  버퍼를 생성하고 memcpy를 사용하여 정점 데이터를 직접 복사하는 가장 쉬운 방법부터 시작하여 스테이징 버퍼를 사용하여 고성능 메모리로 정점 데이터를 복사하는 방법을 살펴 보겠습니다.


Vertex shader


먼저 셰이더 코드 자체에 버텍스 데이터를 포함하지 않도록 버텍스 셰이더를 변경하십시오. 버텍스 쉐이더는 in 키워드를 사용하여 버텍스 버퍼로부터 입력을받습니다.


#version 450
#extension GL_ARB_separate_shader_objects : enable

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

layout(location = 0) out vec3 fragColor;

out gl_PerVertex {
   vec4 gl_Position;
};

void main() {
   gl_Position = vec4(inPosition, 0.0, 1.0);
   fragColor = inColor;
}


inPosition 및 inColor 변수는 정점 속성입니다. 그것들은 두 개의 배열을 사용하여 각 정점 당 위치와 색상을 수동으로 지정했던 것처럼 정점 버퍼에서 정점별로 지정된 속성입니다. 버텍스 쉐이더를 다시 컴파일하십시오!



Vertex data


셰이더 코드의 정점 데이터를 프로그램 코드의 배열로 옮깁니다. 벡터와 행렬과 같은 선형 대수학 관련 유형을 제공하는 GLM 라이브러리를 include 하는 것으로 시작하십시오. 이러한 유형을 사용하여 위치 및 색상 벡터를 지정합니다.


#include <glm/glm.hpp>


내부에 있는 버텍스 쉐이더에서 사용할 두 가지 속성을 가진 Vertex라는 새로운 구조체를 만듭니다.


struct Vertex {
   glm::vec2 pos;
   glm::vec3 color;
};


GLM은 셰이더 언어에서 사용 된 벡터 유형과 정확히 일치하는 C ++ 유형을 편리하게 제공합니다.


const std::vector<Vertex> vertices = {
   {{0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}},
   {{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}},
   {{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}
};


이제 Vertex 구조를 사용하여 정점 데이터의 배열을 지정하십시오. 우리는 이전과 똑같은 위치와 색상 값을 사용하고 있지만 이제는 하나의 정점 배열로 결합됩니다. 이를 인터리빙 하는 버텍스 속성이라고합니다.



Binding descriptions


다음 단계는 GPU 메모리에 업로드 된 Vulkan에게 이 데이터 형식을 버텍스 쉐이더에 전달하는 방법을 알려주는 것입니다. 이 정보를 전달하는 데 필요한 두 가지 유형의 구조가 있습니다.


첫 번째 구조체는 VkVertexInputBindingDescription 이며 Vertex 구조체에 멤버 함수를 추가하여 올바른 데이터로 채웁니다.


struct Vertex {
   glm::vec2 pos;
   glm::vec3 color;

   static VkVertexInputBindingDescription getBindingDescription() {
       VkVertexInputBindingDescription bindingDescription = {};

       return bindingDescription;
   }
};


정점 바인딩은 정점을 통해 메모리에서 데이터를 로드하는 속도를 나타냅니다. 데이터 항목 사이의 바이트 수와 각 정점 이후 또는 각 인스턴스 이후에 다음 데이터 항목으로 이동할지 여부를 지정합니다.


VkVertexInputBindingDescription bindingDescription = {};
bindingDescription.binding = 0;
bindingDescription.stride = sizeof(Vertex);
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;


모든 정점 데이터는 하나의 배열로 묶여 있으므로 하나의 바인딩 만 갖게 됩니다. binding 매개 변수는 바인딩 배열의 바인딩 인덱스를 지정합니다. stride 매개 변수는 한 항목에서 다음 항목까지의 바이트 수를 지정하며 inputRate 매개 변수는 다음 값 중 하나를 가질 수 있습니다.


  • VK_VERTEX_INPUT_RATE_VERTEX : 각 정점 후 다음 데이터 항목으로 이동

  • VK_VERTEX_INPUT_RATE_INSTANCE : 각 인스턴스 종료 후 다음 데이터 항목으로 이동


인스턴싱 된 렌더링을 사용하지 않기 때문에 정점 별 데이터를 유지 할 것입니다.



Attribute description


버텍스 입력을 처리하는 방법을 설명하는 두 번째 구조는 VkVertexInputAttributeDescription 입니다. 이 구조체를 채우기 위해 다른 도우미 함수를 Vertex에 추가 할 것입니다.


#include <array>

...

static std::array<VkVertexInputAttributeDescription, 2> getAttributeDescriptions() {
   std::array<VkVertexInputAttributeDescription, 2> attributeDescriptions = {};

   return attributeDescriptions;
}


함수 프로토타입에서 알 수 있듯이 이러한 구조 중 두 가지가 있습니다. 속성 기술 구조체는 바인딩 기술로부터 기인하는 정점 데이터의 정크로부터 정점 속성을 추출하는 방법을 기술합니다. 위치와 색상이라는 두 가지 속성이 있으므로 두 개의 속성 설명 구조체가 필요합니다.


attributeDescriptions[0].binding = 0;
attributeDescriptions[0].location = 0;
attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
attributeDescriptions[0].offset = offsetof(Vertex, pos);


binding 매개 변수는 Vulkan 에게 각 정점 데이터가 바인딩되는 것을 알려줍니다.

location 매개 변수는 버텍스 쉐이더에서 입력의 위치를 알려 줍니다. 위치 0을 가진 버텍스 쉐이더의 입력은 두 개의 32 비트 부동 요소를 갖는 위치입니다.


format 매개 변수는 속성에 대한 데이터 유형을 설명합니다. 혼란스럽게도 형식은 색상 형식과 동일한 열거를 사용하여 지정됩니다. 다음의 셰이더 타입과 포맷은 일반적으로 함께 사용됩니다 :


  • float : VK_FORMAT_R32_SFLOAT

  • vec2 : VK_FORMAT_R32G32_SFLOAT

  • vec3 : VK_FORMAT_R32G32B32_SFLOAT

  • vec4 : VK_FORMAT_R32G32B32A32_SFLOAT


보시다시피, 셰이더 데이터 형식의 구성 요소 수와 일치하는 색 채널의 형식을 사용해야 합니다. 셰이더의 구성 요소 수보다 많은 채널을 사용할 수 있지만 무시됩니다. 채널 수가 구성 요소 수보다 낮으면 BGA 구성 요소는 (0, 0, 1)의 기본값을 사용합니다. 색상 유형 (SFLOAT, UINT, SINT) 및 비트 폭도 셰이더 입력의 유형과 일치해야 합니다. 다음 예제를 참조하십시오.


  • ivec2 : 32 비트 부호있는 정수의 2 성분 벡터 인 VK_FORMAT_R32G32_SINT

  • uvec4 : 32 비트 부호없는 정수의 4 성분 벡터 인 VK_FORMAT_R32G32B32A32_UINT

  • double : VK_FORMAT_R64_SFLOAT, 배정밀도 (64 비트) 부동 소수점


format 매개 변수는 속성 데이터의 바이트 크기를 암시적으로 정의하며 offset 매개 변수는 읽는 버텍스 별 데이터 시작 이후의 바이트 수를 지정합니다. binding은 한 번에 하나의 Vertex를 로드하며 position 속성 (pos) 은  이 구조체의 시작 부분부터 0 바이트의 오프셋에 있습니다. 이것은 offsetof 매크로를 사용하여 자동으로 계산됩니다.


attributeDescriptions[1].binding = 0;
attributeDescriptions[1].location = 1;
attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[1].offset = offsetof(Vertex, color);


color 속성도 동일한 방식으로 설명됩니다.



Pipeline vertex input


이제는 createGraphicsPipeline의 구조를 참조하여 이 형식으로 정점 데이터를 받아들이도록 그래픽 파이프 라인을 설정해야 합니다. vertexInputInfo 구조체를 찾고 두 개의 설명을 참조하도록 수정하십시오.


auto bindingDescription = Vertex::getBindingDescription();
auto attributeDescriptions = Vertex::getAttributeDescriptions();

vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();


이제 파이프 라인은 버텍스 컨테이너의 형식으로 버텍스 데이터를 받아 들여 버텍스 쉐이더에 전달할 준비가 되었습니다. 현재 유효성 검사 레이어가 활성화 된 상태에서 프로그램을 실행하면 바인딩에 바인딩 된 정점 버퍼가 없다는 메시지가 표시됩니다. 다음 단계는 버텍스 버퍼를 생성하고 버텍스 데이터를 버텍스 데이터로 이동시켜 GPU가 액세스 할 수 있게하는 것입니다.


C++ code / Vertex shader / Fragment shader


이전 글 : Swap chain recreation

다음 글 : Vertex buffer creation





'Vulkan' 카테고리의 다른 글

Staging buffer  (0) 2018.01.25
Vertex buffer creation  (0) 2018.01.25
Swap chain recreation  (0) 2018.01.25
Drawing - Rendering and presentation  (0) 2018.01.25
Drawing - Command buffers  (1) 2018.01.25