Updated instancing example, using instanced attributes (instead of one big ubo), staging, new meshes, etc.
This commit is contained in:
parent
3faee12381
commit
8e2115a0d4
7 changed files with 298 additions and 152 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
Binary file not shown.
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -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;
|
||||||
|
VkDeviceMemory memory = VK_NULL_HANDLE;
|
||||||
|
size_t size = 0;
|
||||||
|
VkDescriptorBufferInfo descriptor;
|
||||||
|
} instanceBuffer;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
glm::mat4 projection;
|
glm::mat4 projection;
|
||||||
glm::mat4 view;
|
glm::mat4 view;
|
||||||
} matrices;
|
float time = 0.0f;
|
||||||
// Seperate data for each instance
|
|
||||||
UboInstanceData *instance;
|
|
||||||
} 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, ¤tBuffer);
|
vkTools::checkResult(swapChain.acquireNextImage(semaphores.presentComplete, ¤tBuffer));
|
||||||
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);
|
||||||
|
|
||||||
|
VkDescriptorImageInfo texDescriptor =
|
||||||
|
vkTools::initializers::descriptorImageInfo(
|
||||||
|
textures.colorMap.sampler,
|
||||||
|
textures.colorMap.view,
|
||||||
|
VK_IMAGE_LAYOUT_GENERAL);
|
||||||
|
|
||||||
|
std::vector<VkWriteDescriptorSet> writeDescriptorSets =
|
||||||
|
{
|
||||||
// Binding 0 : Vertex shader uniform buffer
|
// Binding 0 : Vertex shader uniform buffer
|
||||||
VkWriteDescriptorSet writeDescriptorSet =
|
|
||||||
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,
|
||||||
|
©Region);
|
||||||
|
|
||||||
|
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
|
void updateUniformBuffer(bool viewChanged)
|
||||||
uint8_t *pData;
|
{
|
||||||
uint32_t dataOffset = sizeof(uboVS.matrices);
|
if (viewChanged)
|
||||||
uint32_t dataSize = instanceCount * sizeof(UboInstanceData);
|
{
|
||||||
err = vkMapMemory(device, uniformData.vsScene.memory, dataOffset, dataSize, 0, (void **)&pData);
|
uboVS.projection = glm::perspective(glm::radians(60.0f), (float)width / (float)height, 0.001f, 256.0f);
|
||||||
assert(!err);
|
uboVS.view = glm::translate(glm::mat4(), glm::vec3(0.0f, 0.0f, zoom));
|
||||||
memcpy(pData, uboVS.instance, dataSize);
|
uboVS.view = glm::rotate(uboVS.view, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
|
||||||
vkUnmapMemory(device, uniformData.vsScene.memory);
|
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));
|
||||||
updateUniformBufferMatrices();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateUniformBufferMatrices()
|
uboVS.time += frameTimer * 0.05f;
|
||||||
{
|
|
||||||
// Only updates the uniform buffer block part containing the global matrices
|
|
||||||
|
|
||||||
// Projection
|
memcpy(uniformData.vsScene.mapped, &uboVS, sizeof(uboVS));
|
||||||
uboVS.matrices.projection = glm::perspective(glm::radians(60.0f), (float)width / (float)height, 0.001f, 256.0f);
|
|
||||||
|
|
||||||
// View
|
|
||||||
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();
|
||||||
|
if (!paused)
|
||||||
|
{
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
updateUniformBuffer(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void viewChanged()
|
virtual void viewChanged()
|
||||||
{
|
{
|
||||||
updateUniformBufferMatrices();
|
updateUniformBuffer(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue