Updated instancing example, using instanced attributes (instead of one big ubo), staging, new meshes, etc.

This commit is contained in:
saschawillems 2016-04-17 12:30:42 +02:00
parent 3faee12381
commit 8e2115a0d4
7 changed files with 298 additions and 152 deletions

View file

@ -7,8 +7,11 @@ if %ERRORLEVEL% EQU 0 (
mkdir "assets\shaders\instancing" mkdir "assets\shaders\instancing"
xcopy "..\..\data\shaders\instancing\*.spv" "assets\shaders\instancing" /Y xcopy "..\..\data\shaders\instancing\*.spv" "assets\shaders\instancing" /Y
mkdir "assets\textures"
xcopy "..\..\data\textures\texturearray_rocks_bc3.ktx" "assets\textures" /Y
mkdir "assets\models" mkdir "assets\models"
xcopy "..\..\data\models\angryteapot.3ds" "assets\models" /Y xcopy "..\..\data\models\rock01.dae" "assets\models" /Y
mkdir "res\drawable" mkdir "res\drawable"
xcopy "..\..\android\images\icon.png" "res\drawable" /Y xcopy "..\..\android\images\icon.png" "res\drawable" /Y

View file

@ -3,15 +3,20 @@
#extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable #extension GL_ARB_shading_language_420pack : enable
layout (binding = 1) uniform sampler2DArray samplerArray;
layout (location = 0) in vec3 inNormal; layout (location = 0) in vec3 inNormal;
layout (location = 1) in vec3 inColor; layout (location = 1) in vec3 inColor;
layout (location = 2) in vec3 inEyePos; layout (location = 2) in vec3 inEyePos;
layout (location = 3) in vec3 inLightVec; layout (location = 3) in vec3 inLightVec;
layout (location = 4) in vec3 inUV;
layout (location = 0) out vec4 outFragColor; layout (location = 0) out vec4 outFragColor;
void main() void main()
{ {
vec4 color = texture(samplerArray, inUV) * vec4(inColor, 1.0);
vec3 N = normalize(inNormal); vec3 N = normalize(inNormal);
vec3 L = normalize(vec3(1.0)); vec3 L = normalize(vec3(1.0));
@ -22,7 +27,8 @@ void main()
vec4 IDiffuse = vec4(1.0) * max(dot(inNormal, inLightVec), 0.0); vec4 IDiffuse = vec4(1.0) * max(dot(inNormal, inLightVec), 0.0);
float specular = 0.75; float specular = 0.75;
vec4 ISpecular = vec4(0.5, 0.5, 0.5, 1.0) * pow(max(dot(Reflected, Eye), 0.0), 4.0) * specular; vec4 ISpecular = vec4(0.5, 0.5, 0.5, 1.0) * pow(max(dot(Reflected, Eye), 0.0), 32.0) * specular;
outFragColor = vec4((IAmbient + IDiffuse) * color + ISpecular);
outFragColor = vec4((IAmbient + IDiffuse) * vec4(inColor, 1.0) + ISpecular);
} }

View file

@ -3,35 +3,75 @@
#extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable #extension GL_ARB_shading_language_420pack : enable
// Vertex attributes
layout (location = 0) in vec4 inPos; layout (location = 0) in vec4 inPos;
layout (location = 1) in vec3 inNormal; layout (location = 1) in vec3 inNormal;
layout (location = 2) in vec2 inUV;
layout (location = 3) in vec3 inColor; layout (location = 3) in vec3 inColor;
struct Instance // Instanced attributes
{ layout (location = 4) in vec3 instancePos;
mat4 model; layout (location = 5) in vec3 instanceRot;
vec4 color; layout (location = 6) in float instanceScale;
}; layout (location = 7) in int instanceTexIndex;
layout (binding = 0) uniform UBO layout (binding = 0) uniform UBO
{ {
mat4 projection; mat4 projection;
mat4 view; mat4 view;
Instance instance[343]; float time;
} ubo; } ubo;
layout (location = 0) out vec3 outNormal; layout (location = 0) out vec3 outNormal;
layout (location = 1) out vec3 outColor; layout (location = 1) out vec3 outColor;
layout (location = 2) out vec3 outEyePos; layout (location = 2) out vec3 outEyePos;
layout (location = 3) out vec3 outLightVec; layout (location = 3) out vec3 outLightVec;
layout (location = 4) out vec3 outUV;
void main() void main()
{ {
outNormal = inNormal; outColor = inColor;
outColor = ubo.instance[gl_InstanceIndex].color.rgb; outUV = vec3(inUV, instanceTexIndex);
mat4 modelView = ubo.view * ubo.instance[gl_InstanceIndex].model;
gl_Position = ubo.projection * modelView * inPos; mat4 mx, my, mz;
outEyePos = vec3(modelView * inPos);
vec4 lightPos = vec4(0.0, 0.0, 0.0, 1.0) * modelView; // rotate around x
float s = sin(instanceRot.x);
float c = cos(instanceRot.x);
mx[0] = vec4(c, s, 0.0, 0.0);
mx[1] = vec4(-s, c, 0.0, 0.0);
mx[2] = vec4(0.0, 0.0, 1.0, 0.0);
mx[3] = vec4(0.0, 0.0, 0.0, 1.0);
// rotate around y
s = sin(instanceRot.y + ubo.time);
c = cos(instanceRot.y + ubo.time);
my[0] = vec4(c, 0.0, s, 0.0);
my[1] = vec4(0.0, 1.0, 0.0, 0.0);
my[2] = vec4(-s, 0.0, c, 0.0);
my[3] = vec4(0.0, 0.0, 0.0, 1.0);
// rot around z
s = sin(instanceRot.z);
c = cos(instanceRot.z);
mz[0] = vec4(1.0, 0.0, 0.0, 0.0);
mz[1] = vec4(0.0, c, s, 0.0);
mz[2] = vec4(0.0, -s, c, 0.0);
mz[3] = vec4(0.0, 0.0, 0.0, 1.0);
mat4 rotMat = mz * my * mx;
outNormal = inNormal * mat3(rotMat);
vec4 pos = vec4((inPos.xyz * instanceScale) + instancePos, 1.0) * rotMat;
outEyePos = vec3(ubo.view * pos);
gl_Position = ubo.projection * ubo.view * pos;
vec4 lightPos = vec4(0.0, 0.0, 0.0, 1.0) * ubo.view;
outLightVec = normalize(lightPos.xyz - outEyePos); outLightVec = normalize(lightPos.xyz - outEyePos);
} }

View file

@ -1,5 +1,5 @@
/* /*
* Vulkan Example - Instanced mesh rendering * Vulkan Example - Instanced mesh rendering, uses a separate vertex buffer for instanced data
* *
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de * Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
* *
@ -12,6 +12,7 @@
#include <assert.h> #include <assert.h>
#include <time.h> #include <time.h>
#include <vector> #include <vector>
#include <random>
#define GLM_FORCE_RADIANS #define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE
@ -22,8 +23,9 @@
#include "vulkanexamplebase.h" #include "vulkanexamplebase.h"
#define VERTEX_BUFFER_BIND_ID 0 #define VERTEX_BUFFER_BIND_ID 0
#define INSTANCE_BUFFER_BIND_ID 1
#define ENABLE_VALIDATION false #define ENABLE_VALIDATION false
#define INSTANCING_RANGE 3 #define INSTANCE_COUNT 2048
// Vertex layout for this example // Vertex layout for this example
std::vector<vkMeshLoader::VertexLayout> vertexLayout = std::vector<vkMeshLoader::VertexLayout> vertexLayout =
@ -47,26 +49,30 @@ public:
vkMeshLoader::MeshBuffer example; vkMeshLoader::MeshBuffer example;
} meshes; } meshes;
// Number of mesh instances to be rendered struct {
uint32_t instanceCount; vkTools::VulkanTexture colorMap;
} textures;
struct UboInstanceData{ // Per-instance data block
// Model matrix for each instance struct InstanceData {
glm::mat4 model; glm::vec3 pos;
// Color for each instance glm::vec3 rot;
// vec4 is used due to memory alignment float scale;
// GPU aligns at 16 bytes uint32_t texIndex;
glm::vec4 color;
}; };
// Contains the instanced data
struct { struct {
// Global matrices VkBuffer buffer = VK_NULL_HANDLE;
struct { VkDeviceMemory memory = VK_NULL_HANDLE;
glm::mat4 projection; size_t size = 0;
glm::mat4 view; VkDescriptorBufferInfo descriptor;
} matrices; } instanceBuffer;
// Seperate data for each instance
UboInstanceData *instance; struct {
glm::mat4 projection;
glm::mat4 view;
float time = 0.0f;
} uboVS; } uboVS;
struct { struct {
@ -83,29 +89,20 @@ public:
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
{ {
zoom = -36.0f; zoom = -12.0f;
rotationSpeed = 0.15f; rotationSpeed = 0.25f;
rotation = glm::vec3(-20.0f, 45.0f, 0.0f);
title = "Vulkan Example - Instanced mesh rendering"; title = "Vulkan Example - Instanced mesh rendering";
srand(time(NULL)); srand(time(NULL));
} }
~VulkanExample() ~VulkanExample()
{ {
// Clean up used Vulkan resources
// Note : Inherited destructor cleans up resources stored in base class
vkDestroyPipeline(device, pipelines.solid, nullptr); vkDestroyPipeline(device, pipelines.solid, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
// Meshes
vkMeshLoader::freeMeshBufferResources(device, &meshes.example); vkMeshLoader::freeMeshBufferResources(device, &meshes.example);
// Uniform buffers
vkTools::destroyUniformData(device, &uniformData.vsScene); vkTools::destroyUniformData(device, &uniformData.vsScene);
textureLoader->destroyTexture(textures.colorMap);
delete[] uboVS.instance;
} }
void buildCommandBuffers() void buildCommandBuffers()
@ -118,63 +115,50 @@ public:
VkRenderPassBeginInfo renderPassBeginInfo = vkTools::initializers::renderPassBeginInfo(); VkRenderPassBeginInfo renderPassBeginInfo = vkTools::initializers::renderPassBeginInfo();
renderPassBeginInfo.renderPass = renderPass; renderPassBeginInfo.renderPass = renderPass;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width; renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = height; renderPassBeginInfo.renderArea.extent.height = height;
renderPassBeginInfo.clearValueCount = 2; renderPassBeginInfo.clearValueCount = 2;
renderPassBeginInfo.pClearValues = clearValues; renderPassBeginInfo.pClearValues = clearValues;
VkResult err;
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
{ {
// Set target frame buffer // Set target frame buffer
renderPassBeginInfo.framebuffer = frameBuffers[i]; renderPassBeginInfo.framebuffer = frameBuffers[i];
err = vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo); vkTools::checkResult(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
assert(!err);
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport = vkTools::initializers::viewport( VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
(float)width,
(float)height,
0.0f,
1.0f);
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
VkRect2D scissor = vkTools::initializers::rect2D( VkRect2D scissor = vkTools::initializers::rect2D(width, height, 0, 0);
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); vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.solid); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.solid);
VkDeviceSize offsets[1] = { 0 }; VkDeviceSize offsets[1] = { 0 };
// Binding point 0 : Mesh vertex buffer
vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &meshes.example.vertices.buf, offsets); vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &meshes.example.vertices.buf, offsets);
// Binding point 1 : Instance data buffer
vkCmdBindVertexBuffers(drawCmdBuffers[i], INSTANCE_BUFFER_BIND_ID, 1, &instanceBuffer.buffer, offsets);
vkCmdBindIndexBuffer(drawCmdBuffers[i], meshes.example.indices.buf, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(drawCmdBuffers[i], meshes.example.indices.buf, 0, VK_INDEX_TYPE_UINT32);
// Render instances // Render instances
vkCmdDrawIndexed(drawCmdBuffers[i], meshes.example.indexCount, instanceCount, 0, 0, 0); vkCmdDrawIndexed(drawCmdBuffers[i], meshes.example.indexCount, INSTANCE_COUNT, 0, 0, 0);
vkCmdEndRenderPass(drawCmdBuffers[i]); vkCmdEndRenderPass(drawCmdBuffers[i]);
err = vkEndCommandBuffer(drawCmdBuffers[i]); vkTools::checkResult(vkEndCommandBuffer(drawCmdBuffers[i]));
assert(!err);
} }
} }
void draw() void draw()
{ {
VkResult err;
// Get next image in the swap chain (back/front buffer) // Get next image in the swap chain (back/front buffer)
err = swapChain.acquireNextImage(semaphores.presentComplete, &currentBuffer); vkTools::checkResult(swapChain.acquireNextImage(semaphores.presentComplete, &currentBuffer));
assert(!err);
submitPostPresentBarrier(swapChain.buffers[currentBuffer].image); submitPostPresentBarrier(swapChain.buffers[currentBuffer].image);
@ -183,64 +167,122 @@ public:
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
// Submit to queue // Submit to queue
err = vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); vkTools::checkResult(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
assert(!err);
submitPrePresentBarrier(swapChain.buffers[currentBuffer].image); submitPrePresentBarrier(swapChain.buffers[currentBuffer].image);
err = swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete); vkTools::checkResult(swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete));
assert(!err);
err = vkQueueWaitIdle(queue); vkTools::checkResult(vkQueueWaitIdle(queue));
assert(!err);
} }
void loadMeshes() void loadMeshes()
{ {
loadMesh(getAssetPath() + "models/angryteapot.3ds", &meshes.example, vertexLayout, 0.05f); loadMesh(getAssetPath() + "models/rock01.dae", &meshes.example, vertexLayout, 0.1f);
}
void loadTextures()
{
textureLoader->loadTextureArray(
getAssetPath() + "textures/texturearray_rocks_bc3.ktx",
VK_FORMAT_BC3_UNORM_BLOCK,
&textures.colorMap);
} }
void setupVertexDescriptions() void setupVertexDescriptions()
{ {
// Binding description // Binding description
vertices.bindingDescriptions.resize(1); vertices.bindingDescriptions.resize(2);
// Mesh vertex buffer (description) at binding point 0
vertices.bindingDescriptions[0] = vertices.bindingDescriptions[0] =
vkTools::initializers::vertexInputBindingDescription( vkTools::initializers::vertexInputBindingDescription(
VERTEX_BUFFER_BIND_ID, VERTEX_BUFFER_BIND_ID,
vkMeshLoader::vertexSize(vertexLayout), vkMeshLoader::vertexSize(vertexLayout),
// Input rate for the data passed to shader
// Step for each vertex rendered
VK_VERTEX_INPUT_RATE_VERTEX); VK_VERTEX_INPUT_RATE_VERTEX);
vertices.bindingDescriptions[1] =
vkTools::initializers::vertexInputBindingDescription(
INSTANCE_BUFFER_BIND_ID,
sizeof(InstanceData),
// Input rate for the data passed to shader
// Step for each instance rendered
VK_VERTEX_INPUT_RATE_INSTANCE);
// Attribute descriptions // Attribute descriptions
// Describes memory layout and shader positions // Describes memory layout and shader positions
vertices.attributeDescriptions.resize(4); vertices.attributeDescriptions.clear();
// Per-Vertex attributes
// Location 0 : Position // Location 0 : Position
vertices.attributeDescriptions[0] = vertices.attributeDescriptions.push_back(
vkTools::initializers::vertexInputAttributeDescription( vkTools::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID, VERTEX_BUFFER_BIND_ID,
0, 0,
VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
0); 0)
);
// Location 1 : Normal // Location 1 : Normal
vertices.attributeDescriptions[1] = vertices.attributeDescriptions.push_back(
vkTools::initializers::vertexInputAttributeDescription( vkTools::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID, VERTEX_BUFFER_BIND_ID,
1, 1,
VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
sizeof(float) * 3); sizeof(float) * 3)
);
// Location 2 : Texture coordinates // Location 2 : Texture coordinates
vertices.attributeDescriptions[2] = vertices.attributeDescriptions.push_back(
vkTools::initializers::vertexInputAttributeDescription( vkTools::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID, VERTEX_BUFFER_BIND_ID,
2, 2,
VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32_SFLOAT,
sizeof(float) * 6); sizeof(float) * 6)
);
// Location 3 : Color // Location 3 : Color
vertices.attributeDescriptions[3] = vertices.attributeDescriptions.push_back(
vkTools::initializers::vertexInputAttributeDescription( vkTools::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID, VERTEX_BUFFER_BIND_ID,
3, 3,
VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
sizeof(float) * 8); sizeof(float) * 8)
);
// Instanced attributes
// Location 4 : Position
vertices.attributeDescriptions.push_back(
vkTools::initializers::vertexInputAttributeDescription(
INSTANCE_BUFFER_BIND_ID,
5,
VK_FORMAT_R32G32B32_SFLOAT,
sizeof(float) * 3)
);
// Location 5 : Rotation
vertices.attributeDescriptions.push_back(
vkTools::initializers::vertexInputAttributeDescription(
INSTANCE_BUFFER_BIND_ID,
4,
VK_FORMAT_R32G32B32_SFLOAT,
0)
);
// Location 6 : Scale
vertices.attributeDescriptions.push_back(
vkTools::initializers::vertexInputAttributeDescription(
INSTANCE_BUFFER_BIND_ID,
6,
VK_FORMAT_R32_SFLOAT,
sizeof(float) * 6)
);
// Location 7 : Texture array layer index
vertices.attributeDescriptions.push_back(
vkTools::initializers::vertexInputAttributeDescription(
INSTANCE_BUFFER_BIND_ID,
7,
VK_FORMAT_R32_SINT,
sizeof(float) * 7)
);
vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo(); vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo();
vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size(); vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size();
@ -255,6 +297,7 @@ public:
std::vector<VkDescriptorPoolSize> poolSizes = std::vector<VkDescriptorPoolSize> poolSizes =
{ {
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1),
}; };
VkDescriptorPoolCreateInfo descriptorPoolInfo = VkDescriptorPoolCreateInfo descriptorPoolInfo =
@ -276,6 +319,11 @@ public:
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_VERTEX_BIT,
0), 0),
// Binding 1 : Fragment shader combined sampler
vkTools::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_SHADER_STAGE_FRAGMENT_BIT,
1),
}; };
VkDescriptorSetLayoutCreateInfo descriptorLayout = VkDescriptorSetLayoutCreateInfo descriptorLayout =
@ -306,15 +354,29 @@ public:
VkResult vkRes = vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet); VkResult vkRes = vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet);
assert(!vkRes); assert(!vkRes);
// Binding 0 : Vertex shader uniform buffer VkDescriptorImageInfo texDescriptor =
VkWriteDescriptorSet writeDescriptorSet = vkTools::initializers::descriptorImageInfo(
textures.colorMap.sampler,
textures.colorMap.view,
VK_IMAGE_LAYOUT_GENERAL);
std::vector<VkWriteDescriptorSet> writeDescriptorSets =
{
// Binding 0 : Vertex shader uniform buffer
vkTools::initializers::writeDescriptorSet( vkTools::initializers::writeDescriptorSet(
descriptorSet, descriptorSet,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0, 0,
&uniformData.vsScene.descriptor); &uniformData.vsScene.descriptor),
// Binding 1 : Color map
vkTools::initializers::writeDescriptorSet(
descriptorSet,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1,
&texDescriptor)
};
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, NULL); vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL);
} }
void preparePipelines() void preparePipelines()
@ -328,8 +390,8 @@ public:
VkPipelineRasterizationStateCreateInfo rasterizationState = VkPipelineRasterizationStateCreateInfo rasterizationState =
vkTools::initializers::pipelineRasterizationStateCreateInfo( vkTools::initializers::pipelineRasterizationStateCreateInfo(
VK_POLYGON_MODE_FILL, VK_POLYGON_MODE_FILL,
VK_CULL_MODE_NONE, VK_CULL_MODE_BACK_BIT,
VK_FRONT_FACE_COUNTER_CLOCKWISE, VK_FRONT_FACE_CLOCKWISE,
0); 0);
VkPipelineColorBlendAttachmentState blendAttachmentState = VkPipelineColorBlendAttachmentState blendAttachmentState =
@ -394,84 +456,114 @@ public:
assert(!err); assert(!err);
} }
float rnd(float range)
{
return range * (rand() / double(RAND_MAX));
}
void prepareInstanceData()
{
std::vector<InstanceData> instanceData;
instanceData.resize(INSTANCE_COUNT);
std::mt19937 rndGenerator(time(NULL));
std::uniform_real_distribution<double> uniformDist(0.0, 1.0);
for (auto i = 0; i < INSTANCE_COUNT; i++)
{
instanceData[i].rot = glm::vec3(M_PI * uniformDist(rndGenerator), M_PI * uniformDist(rndGenerator), M_PI * uniformDist(rndGenerator));
float theta = 2 * M_PI * uniformDist(rndGenerator);
float phi = acos(1 - 2 * uniformDist(rndGenerator));
glm::vec3 pos;
instanceData[i].pos = glm::vec3(sin(phi) * cos(theta), sin(theta) * uniformDist(rndGenerator) / 1500.0f, cos(phi)) * 7.5f;
instanceData[i].scale = 1.0f + uniformDist(rndGenerator) * 2.0f;
instanceData[i].texIndex = rnd(textures.colorMap.layerCount);
}
instanceBuffer.size = instanceData.size() * sizeof(InstanceData);
// Staging
// Instanced data is static, copy to device local memory
// This results in better performance
struct {
VkDeviceMemory memory;
VkBuffer buffer;
} stagingBuffer;
VulkanExampleBase::createBuffer(
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
instanceBuffer.size,
instanceData.data(),
&stagingBuffer.buffer,
&stagingBuffer.memory);
VulkanExampleBase::createBuffer(
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_HEAP_DEVICE_LOCAL_BIT,
instanceBuffer.size,
nullptr,
&instanceBuffer.buffer,
&instanceBuffer.memory);
// Copy to staging buffer
VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
VkBufferCopy copyRegion = { };
copyRegion.size = instanceBuffer.size;
vkCmdCopyBuffer(
copyCmd,
stagingBuffer.buffer,
instanceBuffer.buffer,
1,
&copyRegion);
VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);
instanceBuffer.descriptor.range = instanceBuffer.size;
instanceBuffer.descriptor.buffer = instanceBuffer.buffer;
instanceBuffer.descriptor.offset = 0;
}
void prepareUniformBuffers() void prepareUniformBuffers()
{ {
instanceCount = pow((INSTANCING_RANGE * 2) + 1, 3);
uboVS.instance = new UboInstanceData[instanceCount];
VkResult err;
// Vertex shader uniform buffer block
uint32_t uboSize = sizeof(uboVS.matrices) + (instanceCount * sizeof(UboInstanceData));
createBuffer( createBuffer(
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
uboSize, sizeof(uboVS),
nullptr, nullptr,
&uniformData.vsScene.buffer, &uniformData.vsScene.buffer,
&uniformData.vsScene.memory, &uniformData.vsScene.memory,
&uniformData.vsScene.descriptor); &uniformData.vsScene.descriptor);
VkBufferCreateInfo bufferInfo = vkTools::initializers::bufferCreateInfo( // Map for host access
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkTools::checkResult(vkMapMemory(device, uniformData.vsScene.memory, 0, sizeof(uboVS), 0, (void **)&uniformData.vsScene.mapped));
uboSize);
// Colors and model matrices are fixed updateUniformBuffer(true);
float offset = 5.0f;
uint32_t index = 0;
for (int32_t x = -INSTANCING_RANGE; x <= INSTANCING_RANGE; x++)
{
for (int32_t y = -INSTANCING_RANGE; y <= INSTANCING_RANGE; y++)
{
for (int32_t z = -INSTANCING_RANGE; z <= INSTANCING_RANGE; z++)
{
// Instance model matrix
uboVS.instance[index].model = glm::translate(glm::mat4(), glm::vec3(x * offset, y * offset, z * offset));
uboVS.instance[index].model = glm::rotate(uboVS.instance[index].model, glm::radians(-45.0f), glm::vec3(0.0f, 1.0f, 0.0f));
// Instance color (randomized)
uboVS.instance[index].color = glm::vec4((float)(rand() % 255) / 255.0f, (float)(rand() % 255) / 255.0f, (float)(rand() % 255) / 255.0f, 1.0);
index++;
}
}
}
// Update instanced part of the uniform buffer
uint8_t *pData;
uint32_t dataOffset = sizeof(uboVS.matrices);
uint32_t dataSize = instanceCount * sizeof(UboInstanceData);
err = vkMapMemory(device, uniformData.vsScene.memory, dataOffset, dataSize, 0, (void **)&pData);
assert(!err);
memcpy(pData, uboVS.instance, dataSize);
vkUnmapMemory(device, uniformData.vsScene.memory);
updateUniformBufferMatrices();
} }
void updateUniformBufferMatrices() void updateUniformBuffer(bool viewChanged)
{ {
// Only updates the uniform buffer block part containing the global matrices if (viewChanged)
{
uboVS.projection = glm::perspective(glm::radians(60.0f), (float)width / (float)height, 0.001f, 256.0f);
uboVS.view = glm::translate(glm::mat4(), glm::vec3(0.0f, 0.0f, zoom));
uboVS.view = glm::rotate(uboVS.view, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
uboVS.view = glm::rotate(uboVS.view, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
uboVS.view = glm::rotate(uboVS.view, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
}
// Projection uboVS.time += frameTimer * 0.05f;
uboVS.matrices.projection = glm::perspective(glm::radians(60.0f), (float)width / (float)height, 0.001f, 256.0f);
// View memcpy(uniformData.vsScene.mapped, &uboVS, sizeof(uboVS));
uboVS.matrices.view = glm::translate(glm::mat4(), glm::vec3(0.0f, 0.0f, zoom));
uboVS.matrices.view = glm::rotate(uboVS.matrices.view, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
uboVS.matrices.view = glm::rotate(uboVS.matrices.view, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
uboVS.matrices.view = glm::rotate(uboVS.matrices.view, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
// Only update the matrices part of the uniform buffer
uint8_t *pData;
VkResult err = vkMapMemory(device, uniformData.vsScene.memory, 0, sizeof(uboVS.matrices), 0, (void **)&pData);
assert(!err);
memcpy(pData, &uboVS.matrices, sizeof(uboVS.matrices));
vkUnmapMemory(device, uniformData.vsScene.memory);
} }
void prepare() void prepare()
{ {
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
loadTextures();
loadMeshes(); loadMeshes();
prepareInstanceData();
setupVertexDescriptions(); setupVertexDescriptions();
prepareUniformBuffers(); prepareUniformBuffers();
setupDescriptorSetLayout(); setupDescriptorSetLayout();
@ -485,15 +577,20 @@ public:
virtual void render() virtual void render()
{ {
if (!prepared) if (!prepared)
{
return; return;
vkDeviceWaitIdle(device); }
draw(); draw();
vkDeviceWaitIdle(device); if (!paused)
{
vkDeviceWaitIdle(device);
updateUniformBuffer(false);
}
} }
virtual void viewChanged() virtual void viewChanged()
{ {
updateUniformBufferMatrices(); updateUniformBuffer(true);
} }
}; };