Mesh loading and rendering now properly displaying glTF mesh
Added textures, modified structure to be more in line with glTF layout Split matrices and material descriptor set
This commit is contained in:
parent
d50a5d0f40
commit
9f7d13d5e0
1 changed files with 117 additions and 110 deletions
|
|
@ -38,17 +38,26 @@
|
||||||
|
|
||||||
#define ENABLE_VALIDATION false
|
#define ENABLE_VALIDATION false
|
||||||
|
|
||||||
|
// Contains everything required to render a glTF model in Vulkan
|
||||||
|
// This class is very simplified but retains the basic glTF structure
|
||||||
|
class VulkanglTFModel
|
||||||
|
{
|
||||||
|
// The vertex layout for the samples' model
|
||||||
|
struct Vertex {
|
||||||
|
glm::vec3 pos;
|
||||||
|
glm::vec3 normal;
|
||||||
|
glm::vec2 uv;
|
||||||
|
glm::vec3 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class VulkanExample : public VulkanExampleBase
|
class VulkanExample : public VulkanExampleBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool wireframe = false;
|
bool wireframe = false;
|
||||||
|
|
||||||
struct {
|
|
||||||
vks::Texture2D colorMap;
|
|
||||||
} textures;
|
|
||||||
|
|
||||||
// Vertex layout used in this example
|
|
||||||
// This must fit input locations of the vertex shader used to render the model
|
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
glm::vec3 pos;
|
glm::vec3 pos;
|
||||||
glm::vec3 normal;
|
glm::vec3 normal;
|
||||||
|
|
@ -58,27 +67,42 @@ public:
|
||||||
|
|
||||||
struct ModelNode;
|
struct ModelNode;
|
||||||
|
|
||||||
// Represents a single mesh-based node in the glTF scene graph
|
// A primitive contains the data for a single draw call
|
||||||
// This is simplified as much as possible to make this sample easy to understand
|
struct Primitive {
|
||||||
struct ModelNode {
|
|
||||||
ModelNode* parent;
|
|
||||||
uint32_t firstIndex;
|
uint32_t firstIndex;
|
||||||
uint32_t indexCount;
|
uint32_t indexCount;
|
||||||
glm::mat4 matrix;
|
int32_t materialIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Contains the node's geometry and can be made up of an arbitrary number of primitives
|
||||||
|
struct Mesh {
|
||||||
|
std::vector<Primitive> primitives;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A node represents an object in the glTF scene graph
|
||||||
|
struct ModelNode {
|
||||||
|
ModelNode* parent;
|
||||||
std::vector<ModelNode> children;
|
std::vector<ModelNode> children;
|
||||||
|
Mesh mesh;
|
||||||
|
glm::mat4 matrix;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Represents a glTF material used to access e.g. the texture to choose for a mesh
|
// Represents a glTF material used to access e.g. the texture to choose for a mesh
|
||||||
// Only includes the most basic properties required for this sample
|
|
||||||
struct ModelMaterial {
|
struct ModelMaterial {
|
||||||
glm::vec4 baseColorFactor = glm::vec4(1.0f);
|
glm::vec4 baseColorFactor = glm::vec4(1.0f);
|
||||||
uint32_t baseColorTextureIndex;
|
uint32_t baseColorTextureIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// @todo
|
||||||
|
struct ModelImage {
|
||||||
|
vks::Texture2D texture;
|
||||||
|
VkDescriptorSet descriptorSet;
|
||||||
|
};
|
||||||
|
|
||||||
// Contains all Vulkan resources required to represent vertex and index buffers for a model
|
// Contains all Vulkan resources required to represent vertex and index buffers for a model
|
||||||
// This is for demonstration and learning purposes, the other examples use a model loader class for easy access
|
// This is for demonstration and learning purposes, the other examples use a model loader class for easy access
|
||||||
struct Model {
|
struct Model {
|
||||||
std::vector<vks::Texture2D> images;
|
std::vector<ModelImage> images;
|
||||||
// Textures in glTF are indices used by material to select an image (and optionally samplers)
|
// Textures in glTF are indices used by material to select an image (and optionally samplers)
|
||||||
std::vector<uint32_t> textures;
|
std::vector<uint32_t> textures;
|
||||||
std::vector<ModelMaterial> materials;
|
std::vector<ModelMaterial> materials;
|
||||||
|
|
@ -119,7 +143,11 @@ public:
|
||||||
|
|
||||||
VkPipelineLayout pipelineLayout;
|
VkPipelineLayout pipelineLayout;
|
||||||
VkDescriptorSet descriptorSet;
|
VkDescriptorSet descriptorSet;
|
||||||
VkDescriptorSetLayout descriptorSetLayout;
|
|
||||||
|
struct DescriptorSetLayouts {
|
||||||
|
VkDescriptorSetLayout matrices;
|
||||||
|
VkDescriptorSetLayout textures;
|
||||||
|
} descriptorSetLayouts;
|
||||||
|
|
||||||
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
||||||
{
|
{
|
||||||
|
|
@ -128,8 +156,9 @@ public:
|
||||||
rotationSpeed = 0.5f;
|
rotationSpeed = 0.5f;
|
||||||
rotation = { -0.5f, -112.75f, 0.0f };
|
rotation = { -0.5f, -112.75f, 0.0f };
|
||||||
cameraPos = { 0.1f, 1.1f, 0.0f };
|
cameraPos = { 0.1f, 1.1f, 0.0f };
|
||||||
title = "Model rendering";
|
title = "glTF model rendering";
|
||||||
settings.overlay = true;
|
settings.overlay = true;
|
||||||
|
//@todo: Use camera
|
||||||
}
|
}
|
||||||
|
|
||||||
~VulkanExample()
|
~VulkanExample()
|
||||||
|
|
@ -142,11 +171,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
||||||
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.matrices, nullptr);
|
||||||
|
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.textures, nullptr);
|
||||||
|
|
||||||
model.destroy(device);
|
model.destroy(device);
|
||||||
|
|
||||||
textures.colorMap.destroy();
|
|
||||||
uniformBuffers.scene.destroy();
|
uniformBuffers.scene.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,33 +204,20 @@ public:
|
||||||
renderPassBeginInfo.clearValueCount = 2;
|
renderPassBeginInfo.clearValueCount = 2;
|
||||||
renderPassBeginInfo.pClearValues = clearValues;
|
renderPassBeginInfo.pClearValues = clearValues;
|
||||||
|
|
||||||
|
const VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
|
||||||
|
const VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0);
|
||||||
|
|
||||||
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
|
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
|
||||||
{
|
{
|
||||||
// Set target frame buffer
|
|
||||||
renderPassBeginInfo.framebuffer = frameBuffers[i];
|
renderPassBeginInfo.framebuffer = frameBuffers[i];
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
|
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
|
||||||
|
|
||||||
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
|
|
||||||
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
|
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
|
||||||
VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0);
|
|
||||||
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
|
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
|
||||||
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL);
|
// Bind scene matrices descriptor to set 0
|
||||||
|
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
|
||||||
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, wireframe ? pipelines.wireframe : pipelines.solid);
|
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, wireframe ? pipelines.wireframe : pipelines.solid);
|
||||||
|
|
||||||
drawglTFModel(drawCmdBuffers[i]);
|
drawglTFModel(drawCmdBuffers[i]);
|
||||||
|
|
||||||
/*
|
|
||||||
VkDeviceSize offsets[1] = { 0 };
|
|
||||||
// Bind mesh vertex buffer
|
|
||||||
vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &model.vertices.buffer, offsets);
|
|
||||||
// Bind mesh index buffer
|
|
||||||
vkCmdBindIndexBuffer(drawCmdBuffers[i], model.indices.buffer, 0, VK_INDEX_TYPE_UINT32);
|
|
||||||
// Render mesh vertex buffer using its indices
|
|
||||||
vkCmdDrawIndexed(drawCmdBuffers[i], model.indices.count, 1, 0, 0, 0);
|
|
||||||
*/
|
|
||||||
|
|
||||||
drawUI(drawCmdBuffers[i]);
|
drawUI(drawCmdBuffers[i]);
|
||||||
vkCmdEndRenderPass(drawCmdBuffers[i]);
|
vkCmdEndRenderPass(drawCmdBuffers[i]);
|
||||||
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
||||||
|
|
@ -210,8 +226,15 @@ public:
|
||||||
|
|
||||||
void drawglTFNode(VkCommandBuffer commandBuffer, ModelNode node)
|
void drawglTFNode(VkCommandBuffer commandBuffer, ModelNode node)
|
||||||
{
|
{
|
||||||
if (node.indexCount > 0) {
|
if (node.mesh.primitives.size() > 0) {
|
||||||
vkCmdDrawIndexed(commandBuffer, node.indexCount, 1, node.firstIndex, 0, 0);
|
for (Primitive& primitive : node.mesh.primitives) {
|
||||||
|
if (primitive.indexCount > 0) {
|
||||||
|
// @todo: link mat to node
|
||||||
|
uint32_t texture = model.textures[model.materials[primitive.materialIndex].baseColorTextureIndex];
|
||||||
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &model.images[texture].descriptorSet, 0, nullptr);
|
||||||
|
vkCmdDrawIndexed(commandBuffer, primitive.indexCount, 1, primitive.firstIndex, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (auto& child : node.children) {
|
for (auto& child : node.children) {
|
||||||
drawglTFNode(commandBuffer, child);
|
drawglTFNode(commandBuffer, child);
|
||||||
|
|
@ -262,7 +285,8 @@ public:
|
||||||
buffer = &glTFImage.image[0];
|
buffer = &glTFImage.image[0];
|
||||||
bufferSize = glTFImage.image.size();
|
bufferSize = glTFImage.image.size();
|
||||||
}
|
}
|
||||||
model.images[i].fromBuffer(buffer, bufferSize, VK_FORMAT_R8G8B8A8_UNORM, glTFImage.width, glTFImage.height, vulkanDevice, queue);
|
// Load texture from image buffer
|
||||||
|
model.images[i].texture.fromBuffer(buffer, bufferSize, VK_FORMAT_R8G8B8A8_UNORM, glTFImage.width, glTFImage.height, vulkanDevice, queue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -334,12 +358,12 @@ public:
|
||||||
// In glTF this is done via accessors and buffer views
|
// In glTF this is done via accessors and buffer views
|
||||||
if (glTFNode.mesh > -1) {
|
if (glTFNode.mesh > -1) {
|
||||||
const tinygltf::Mesh mesh = glTFModel.meshes[glTFNode.mesh];
|
const tinygltf::Mesh mesh = glTFModel.meshes[glTFNode.mesh];
|
||||||
uint32_t indexStart = static_cast<uint32_t>(indexBuffer.size());
|
|
||||||
uint32_t vertexStart = static_cast<uint32_t>(vertexBuffer.size());
|
|
||||||
uint32_t indexCount = 0;
|
|
||||||
// Iterate through all primitives of this node's mesh
|
// Iterate through all primitives of this node's mesh
|
||||||
for (size_t i = 0; i < mesh.primitives.size(); i++) {
|
for (size_t i = 0; i < mesh.primitives.size(); i++) {
|
||||||
const tinygltf::Primitive& primitive = mesh.primitives[i];
|
const tinygltf::Primitive& glTFPrimitive = mesh.primitives[i];
|
||||||
|
uint32_t firstIndex = static_cast<uint32_t>(indexBuffer.size());
|
||||||
|
uint32_t vertexStart = static_cast<uint32_t>(vertexBuffer.size());
|
||||||
|
uint32_t indexCount = 0;
|
||||||
// Vertices
|
// Vertices
|
||||||
{
|
{
|
||||||
const float* positionBuffer = nullptr;
|
const float* positionBuffer = nullptr;
|
||||||
|
|
@ -348,22 +372,22 @@ public:
|
||||||
size_t vertexCount = 0;
|
size_t vertexCount = 0;
|
||||||
|
|
||||||
// Get buffer data for vertex normals
|
// Get buffer data for vertex normals
|
||||||
if (primitive.attributes.find("POSITION") != primitive.attributes.end()) {
|
if (glTFPrimitive.attributes.find("POSITION") != glTFPrimitive.attributes.end()) {
|
||||||
const tinygltf::Accessor& accessor = glTFModel.accessors[primitive.attributes.find("POSITION")->second];
|
const tinygltf::Accessor& accessor = glTFModel.accessors[glTFPrimitive.attributes.find("POSITION")->second];
|
||||||
const tinygltf::BufferView& view = glTFModel.bufferViews[accessor.bufferView];
|
const tinygltf::BufferView& view = glTFModel.bufferViews[accessor.bufferView];
|
||||||
positionBuffer = reinterpret_cast<const float*>(&(glTFModel.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
|
positionBuffer = reinterpret_cast<const float*>(&(glTFModel.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
|
||||||
vertexCount = accessor.count;
|
vertexCount = accessor.count;
|
||||||
}
|
}
|
||||||
// Get buffer data for vertex normals
|
// Get buffer data for vertex normals
|
||||||
if (primitive.attributes.find("NORMAL") != primitive.attributes.end()) {
|
if (glTFPrimitive.attributes.find("NORMAL") != glTFPrimitive.attributes.end()) {
|
||||||
const tinygltf::Accessor& accessor = glTFModel.accessors[primitive.attributes.find("NORMAL")->second];
|
const tinygltf::Accessor& accessor = glTFModel.accessors[glTFPrimitive.attributes.find("NORMAL")->second];
|
||||||
const tinygltf::BufferView& view = glTFModel.bufferViews[accessor.bufferView];
|
const tinygltf::BufferView& view = glTFModel.bufferViews[accessor.bufferView];
|
||||||
normalsBuffer = reinterpret_cast<const float*>(&(glTFModel.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
|
normalsBuffer = reinterpret_cast<const float*>(&(glTFModel.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
|
||||||
}
|
}
|
||||||
// Get buffer data for vertex texture coordinates
|
// Get buffer data for vertex texture coordinates
|
||||||
// glTF supports multiple sets, we only load the first one
|
// glTF supports multiple sets, we only load the first one
|
||||||
if (primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end()) {
|
if (glTFPrimitive.attributes.find("TEXCOORD_0") != glTFPrimitive.attributes.end()) {
|
||||||
const tinygltf::Accessor& accessor = glTFModel.accessors[primitive.attributes.find("TEXCOORD_0")->second];
|
const tinygltf::Accessor& accessor = glTFModel.accessors[glTFPrimitive.attributes.find("TEXCOORD_0")->second];
|
||||||
const tinygltf::BufferView& view = glTFModel.bufferViews[accessor.bufferView];
|
const tinygltf::BufferView& view = glTFModel.bufferViews[accessor.bufferView];
|
||||||
texCoordsBuffer = reinterpret_cast<const float*>(&(glTFModel.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
|
texCoordsBuffer = reinterpret_cast<const float*>(&(glTFModel.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
|
||||||
}
|
}
|
||||||
|
|
@ -374,17 +398,21 @@ public:
|
||||||
vert.pos = glm::vec4(glm::make_vec3(&positionBuffer[v * 3]), 1.0f);
|
vert.pos = glm::vec4(glm::make_vec3(&positionBuffer[v * 3]), 1.0f);
|
||||||
vert.normal = glm::normalize(glm::vec3(normalsBuffer ? glm::make_vec3(&normalsBuffer[v * 3]) : glm::vec3(0.0f)));
|
vert.normal = glm::normalize(glm::vec3(normalsBuffer ? glm::make_vec3(&normalsBuffer[v * 3]) : glm::vec3(0.0f)));
|
||||||
vert.uv = texCoordsBuffer ? glm::make_vec2(&texCoordsBuffer[v * 2]) : glm::vec3(0.0f);
|
vert.uv = texCoordsBuffer ? glm::make_vec2(&texCoordsBuffer[v * 2]) : glm::vec3(0.0f);
|
||||||
|
vert.color = glm::vec3(1.0f);
|
||||||
|
// Flip Y-Axis
|
||||||
|
vert.pos.y *= -1.0f;
|
||||||
vertexBuffer.push_back(vert);
|
vertexBuffer.push_back(vert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Indices
|
// Indices
|
||||||
{
|
{
|
||||||
const tinygltf::Accessor& accessor = glTFModel.accessors[primitive.indices];
|
const tinygltf::Accessor& accessor = glTFModel.accessors[glTFPrimitive.indices];
|
||||||
const tinygltf::BufferView& bufferView = glTFModel.bufferViews[accessor.bufferView];
|
const tinygltf::BufferView& bufferView = glTFModel.bufferViews[accessor.bufferView];
|
||||||
const tinygltf::Buffer& buffer = glTFModel.buffers[bufferView.buffer];
|
const tinygltf::Buffer& buffer = glTFModel.buffers[bufferView.buffer];
|
||||||
|
|
||||||
indexCount += static_cast<uint32_t>(accessor.count);
|
indexCount += static_cast<uint32_t>(accessor.count);
|
||||||
|
|
||||||
|
// glTF supports different component types of indices
|
||||||
switch (accessor.componentType) {
|
switch (accessor.componentType) {
|
||||||
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: {
|
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: {
|
||||||
uint32_t* buf = new uint32_t[accessor.count];
|
uint32_t* buf = new uint32_t[accessor.count];
|
||||||
|
|
@ -415,9 +443,12 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Primitive primitive{};
|
||||||
|
primitive.firstIndex = firstIndex;
|
||||||
|
primitive.indexCount = indexCount;
|
||||||
|
primitive.materialIndex = glTFPrimitive.material;
|
||||||
|
node.mesh.primitives.push_back(primitive);
|
||||||
}
|
}
|
||||||
node.firstIndex = indexStart;
|
|
||||||
node.indexCount = indexCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent) {
|
if (parent) {
|
||||||
|
|
@ -548,76 +579,54 @@ public:
|
||||||
void loadAssets()
|
void loadAssets()
|
||||||
{
|
{
|
||||||
loadglTF(getAssetPath() + "models/voyager/voyager.gltf");
|
loadglTF(getAssetPath() + "models/voyager/voyager.gltf");
|
||||||
textures.colorMap.loadFromFile(getAssetPath() + "models/voyager/voyager_rgba_unorm.ktx", VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupDescriptorPool()
|
void setupDescriptors()
|
||||||
{
|
{
|
||||||
// Example uses one ubo and one combined image sampler
|
/*
|
||||||
std::vector<VkDescriptorPoolSize> poolSizes =
|
This sample uses separate descriptor sets (and layouts) for the matrices and materials (textures)
|
||||||
{
|
*/
|
||||||
|
|
||||||
|
std::vector<VkDescriptorPoolSize> poolSizes = {
|
||||||
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
|
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
|
||||||
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1),
|
// One combined image sampler per model image/texture
|
||||||
|
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, static_cast<uint32_t>(model.images.size())),
|
||||||
};
|
};
|
||||||
|
// One set for matrices and one per model image/texture
|
||||||
VkDescriptorPoolCreateInfo descriptorPoolInfo =
|
const uint32_t maxSetCount = static_cast<uint32_t>(model.images.size()) + 1;
|
||||||
vks::initializers::descriptorPoolCreateInfo(
|
VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, maxSetCount);
|
||||||
static_cast<uint32_t>(poolSizes.size()),
|
|
||||||
poolSizes.data(),
|
|
||||||
1);
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
|
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
|
||||||
}
|
|
||||||
|
|
||||||
void setupDescriptorSetLayout()
|
// Descriptor set layout for passing matrices
|
||||||
{
|
VkDescriptorSetLayoutBinding setLayoutBinding = vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0);
|
||||||
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings =
|
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(&setLayoutBinding, 1);
|
||||||
{
|
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.matrices));
|
||||||
// Binding 0 : Vertex shader uniform buffer
|
// Descriptor set layout for passing material textures
|
||||||
vks::initializers::descriptorSetLayoutBinding(
|
setLayoutBinding = vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 0);
|
||||||
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.textures));
|
||||||
VK_SHADER_STAGE_VERTEX_BIT,
|
// Pipeline layout using both descriptor sets (set 0 = matrices, set 1 = material)
|
||||||
0),
|
std::array<VkDescriptorSetLayout, 2> setLayouts = { descriptorSetLayouts.matrices, descriptorSetLayouts.textures };
|
||||||
// Binding 1 : Fragment shader combined sampler
|
VkPipelineLayoutCreateInfo pipelineLayoutCI= vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), static_cast<uint32_t>(setLayouts.size()));
|
||||||
vks::initializers::descriptorSetLayoutBinding(
|
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout));
|
||||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
||||||
VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
||||||
1),
|
|
||||||
};
|
|
||||||
|
|
||||||
VkDescriptorSetLayoutCreateInfo descriptorLayout =
|
// Descriptor set for scene matrices
|
||||||
vks::initializers::descriptorSetLayoutCreateInfo(
|
VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.matrices, 1);
|
||||||
setLayoutBindings.data(),
|
|
||||||
static_cast<uint32_t>(setLayoutBindings.size()));
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout));
|
|
||||||
|
|
||||||
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
|
|
||||||
vks::initializers::pipelineLayoutCreateInfo(
|
|
||||||
&descriptorSetLayout,
|
|
||||||
1);
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupDescriptorSet()
|
|
||||||
{
|
|
||||||
VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
|
|
||||||
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
|
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
|
||||||
|
VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.scene.descriptor);
|
||||||
std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
|
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
|
||||||
// Binding 0 : Vertex shader uniform buffer
|
// Descriptor sets for materials
|
||||||
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.scene.descriptor),
|
for (auto& image : model.images) {
|
||||||
// Binding 1 : Color map
|
const VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.textures, 1);
|
||||||
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textures.colorMap.descriptor)
|
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &image.descriptorSet));
|
||||||
};
|
VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet(image.descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &image.texture.descriptor);
|
||||||
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
|
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void preparePipelines()
|
void preparePipelines()
|
||||||
{
|
{
|
||||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE);
|
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE);
|
||||||
VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_CLOCKWISE, 0);
|
VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0);
|
||||||
VkPipelineColorBlendAttachmentState blendAttachmentStateCI = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE);
|
VkPipelineColorBlendAttachmentState blendAttachmentStateCI = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE);
|
||||||
VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentStateCI);
|
VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentStateCI);
|
||||||
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL);
|
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL);
|
||||||
|
|
@ -717,10 +726,8 @@ public:
|
||||||
VulkanExampleBase::prepare();
|
VulkanExampleBase::prepare();
|
||||||
loadAssets();
|
loadAssets();
|
||||||
prepareUniformBuffers();
|
prepareUniformBuffers();
|
||||||
setupDescriptorSetLayout();
|
setupDescriptors();
|
||||||
preparePipelines();
|
preparePipelines();
|
||||||
setupDescriptorPool();
|
|
||||||
setupDescriptorSet();
|
|
||||||
buildCommandBuffers();
|
buildCommandBuffers();
|
||||||
prepared = true;
|
prepared = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue