2021. 8. 14. 03:17ㆍ그래픽스/vk
Vertex input description
1. Introduction
- 셰이더에 하드코딩된 vertex data를 vertex buffer로 수정할것이다
- 가장 쉬운 접근법인 CPU visible buffer 를생성하고 memcpy 로 데이터를 직접 복사하는것부터 시작할것이다.
- 그리고 이후에 고성능 메모리에 vertex data를 복사하기 위해
- 어떻게 staging buffer 를 사용할것인지를 살펴볼것이다.
2. Vertex shader
- 일단 vertex shader에서 하드코딩된 부분을 지우자
- vertex shader는 in 키워드를 사용하여 vertex buffer로부터 입력을 받는다.
#version 450
layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 0) out vec3 fragColor;
void main() {
gl_Position = vec4(inPosition, 0.0, 1.0);
fragColor = inColor;
}
- inPosition 및 inColor 변수는 vertex attributes이다.
- 그들은 vertex buffer에서 지정한 vertex마다 지정된 속성이다.
(우리가 직접 두개의 배열로 vertex마다 color와 position을 하드코딩한것처럼)
- 이제 vertex shader를 다시 컴파일해야한다.
- fragColor 처럼 layout(location = x) annotations 은 나중에 입력을 목적으로 참조할수있도록하는 인덱스에 해당함 - dvec3 같은 타입은 64 비트 벡터와 같은 일부 타입들은 다중 슬롯을 사용한다는것을 알아야한다. - 이는 location 인덱스를 2만큼 차지한다는것을 의미하며, 다음 인덱스가 최소한 2 이상 더 높아야한다 layout(location = 0) in dvec3 inPosition; layout(location = 2) in vec3 inColor; - OpenGL wiki. 에서 layout 한정자에 대해 알아볼 수 있다. |
3. Vertex data
- vertex data를 shader code에서 우리의 프로그램 코드의 배열로 옮겨야한다.
- 벡터 및 행렬과 같은 선형 대수 관련 유형을 제공하는 GLM 라이브러리를 포함하여 시작해야한다.
#include <glm/glm.hpp>
- 새로운 구조체인 Vertex를 만들어 vertex shader내부에서 사용할 두 속성 을 멤버로 구성하자
struct Vertex {
glm::vec2 pos;
glm::vec3 color;
};
- GLM은 shader 언어에서 사용되는 벡터 타입과 정확히 일치하는 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 구조체를 사용하여 vertex data의 배열을 명시하자.
- 우리는 이제 이전과 정확히 같은 color 와 position을 가지게 되었지만
- 지금은 이제 하나의 배열로 결합되었다.
- 이런 방식을 "interleaving vertex attributes" 라고 부른다.
4. Binding descriptions
- 이런 데이터 포맷을 일단 GPU메모리로 업로드 하고 vertex shader에 전달하는 방법을 Vulkan에게 알려야한다.
- 이런 정보를 전달하는데에는 두가지 구조체가 필요하다.
- 첫번째 구조체는 VkVertexInputBindingDescription 이다.
- Vertex 구조체에 올바른 데이터로 Description구조체를 채우기 위한 멤버함수를 추가해야한다.
struct Vertex {
glm::vec2 pos;
glm::vec3 color;
static VkVertexInputBindingDescription getBindingDescription() {
VkVertexInputBindingDescription bindingDescription{};
return bindingDescription;
}
};
- vertex binding 은 vertices의 전체 메모리로부터 데이터를 로드하는 속도(rate)를 기술한다.
(A vertex binding describes at which rate to load data from memory throughout the vertices)
- 이것은 데이터 항목 사이에 몇개의 바이트가 있는지를 명시하고
(It specifies the number of bytes between data entries and)
- 이것은 데이터가 정점단위인지, 인스턴스단위인지 명시하여 데이터를 이동시키는 속도?를 기술한다.
(whether to move to the next data entry after each vertex or after each instance)
VkVertexInputBindingDescription bindingDescription{};
bindingDescription.binding = 0;
bindingDescription.stride = sizeof(Vertex);
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
- 모든 vertex마다의 데이터는 하나의 배열에 함께 저장되어있음.
- 그래서 하나의 바인딩만 생성하면된다. (binding 의 인덱스 0)
- binding: 이 구조체가 기술할 바인딩 번호 (binding의 배열에서 바인딩 인덱스를 지정함)
- stride : entry에서 다음 entry 사이에 몇개의 bytes이 있는지 지정
- inputRate : 아래와 같은 변수를 파라미터로 가질 수 있음
- VK_VERTEX_INPUT_RATE_VERTEX: Move to the next data entry after each vertex
- VK_VERTEX_INPUT_RATE_INSTANCE: Move to the next data entry after each instance
- instanced rendering 을 할경우 후자를 사용한다.
- 우리는 지금 instanced renndering을 사용하지 않기 때문에
- per-vertex 데이터를 고수할 것임.
5. Attribute descriptions
- 두번째 구조체 VkVertexInputAttributeDescription는 어떻게 vertex 입력을 처리할지를 기술한다.
- Vertex 구조체에 도우미 함수를 하나 더 추가하자.
#include <array>
...
static std::array<VkVertexInputAttributeDescription, 2> getAttributeDescriptions() {
std::array<VkVertexInputAttributeDescription, 2> attributeDescriptions{};
return attributeDescriptions;
}
- 프로토타입 함수에서 볼 수 있듯이, 두개의 구조체를 생성할것임.
- 이 구조체는 binding description에서 생성된 vertex data의 큰 덩어리로부터 어떻게 vertex attribute를 추출할것인지를 기술한다.
- 여기서는 두가지 attributes, position 과 color를 추출해야하므로 두개의 구조체가 필요하다.
attributeDescriptions[0].binding = 0;
attributeDescriptions[0].location = 0;
attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
attributeDescriptions[0].offset = offsetof(Vertex, pos);
- binding : Vulkan 에게 정점별 바인딩이 어디에서 오는지 알려줌
(이 속성이 데이터를 가져오는 바인딩 번호)
- location : vertex shader안 input 에서의 location 지시자 번호
(shader 안에서 location 0 은 position이고, 두개의 32-bit float를 가짐.)
- format : attribute의 데이터 타입을 설명함. 일반적으로 다음과 같은 셰이더 타입이 함께 사용됨.
(color formats의 열거형을 사용)
- float: VK_FORMAT_R32_SFLOAT
- vec2: VK_FORMAT_R32G32_SFLOAT
- vec3: VK_FORMAT_R32G32B32_SFLOAT
- vec4: VK_FORMAT_R32G32B32A32_SFLOAT
- - - - format을 사용할때, color의 채널의 개수와, shader data 타입의 컴포넌트의 개수가 같아야한다.
- - - - 더 많은 채널을 사용하는것은 허용되지만, 암시적으로 제거됨.
- - - - 만일 채널의 수가 더 적으면, BGA 컴포넌트는 기본값으로 (0, 0, 1) 를 사용함.
- - - - 이 칼라 타입(SFLOAT, UINT, SINT) 과 bit width 또한 shader input 타입과 일치해야한다.
- ivec2: VK_FORMAT_R32G32_SINT, a 2-component vector of 32-bit signed integers
- uvec4: VK_FORMAT_R32G32B32A32_UINT, a 4-component vector of 32-bit unsigned integers
- double: VK_FORMAT_R64_SFLOAT, a double-precision (64-bit) float
- - - - format 파라미터는 암시적으로 attribute data의 바이트 사이즈를 정의한다.
- offset : 읽을 정점별 데이터에서 의 시작점
( the offset parameter specifies the number of bytes since the start of the per-vertex data to read from)
attributeDescriptions[1].binding = 0;
attributeDescriptions[1].location = 1;
attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[1].offset = offsetof(Vertex, color);
- 색상 속성 또한 같은 방식,
offsetof(struct, member) : stddef.h의 매크로 함수. - member 변수가 구조체에서 메모리상 얼마나 떨어져있는지 계산해줌 |
6. Pipeline vertex input
- 이제 이 format에서 정점데이터를 얻어오기 위해서
- createGraphicsPipeline 함수 안의 vertexInputInfo 구조체를 참조하여 graphics pipeline를 손봐야함
- 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();
- 이 파이프라인은 이제 vertices의 포맷의 vertex data를 받아들일 준비가 되어있고,
- vertex shader로 전달할 준비가 되어있다.
- 만일 지금 유효성 검사를 활성화하고, 프로그램을 실행하면
- 바인딩된 정점버퍼이 없다는 오류를 볼 수있을 것이다.
- 다음 스텝에선 vertex buffer를 만들고, vertex data를 거기로 옮겨
- GPU가 접근가능하게 할것이다.
'그래픽스 > vk' 카테고리의 다른 글
[vk] Vertex buffers - Staging buffer (0) | 2021.08.14 |
---|---|
[vk] Vertex buffers - Vertex buffer creation (0) | 2021.08.14 |
[vk] Drawing triangle - Drawing - Swap chain recreation (0) | 2021.08.11 |
[vk] Drawing triangle - Drawing - Rendering and presentation (0) | 2021.08.11 |
[vk] Drawing triangle - Drawing - Command buffers (0) | 2021.08.11 |