Visually upgraded deferred rendering example with moving lights, multiple meshes and normal mapping

This commit is contained in:
saschawillems 2016-07-03 21:32:35 +02:00
parent f06ffae58e
commit 18013c44e0
12 changed files with 247 additions and 196 deletions

View file

@ -171,9 +171,9 @@ Implements a bloom effect to simulate glowing parts of a 3D mesh. A two pass gau
<br><br>
## [Deferred shading](deferred/)
<img src="./screenshots/deferred_shading.png" height="96px" align="right">
<img src="./screenshots/deferred_shading.jpg" height="96px" align="right">
Demonstrates the use of multiple render targets to fill a G-Buffer for deferred shading.
Demonstrates the use of multiple render targets to fill a G-Buffer for a deferred shading setup with multiple dynamic lights and normal mapped surfaces.
Deferred shading collects all values (color, normal, position) into different render targets in one pass thanks to multiple render targets, and then does all shading and lighting calculations based on these in screen space, thus allowing for much more light sources than traditional forward renderers.
<br><br>

View file

@ -17,6 +17,7 @@ void main()
components[0] = texture(samplerPosition, inUV.st).rgb;
components[1] = texture(samplerNormal, inUV.st).rgb;
components[2] = texture(samplerAlbedo, inUV.st).rgb;
// Uncomment to display specular component
//components[2] = vec3(texture(samplerAlbedo, inUV.st).a);
// Select component depending on z coordinate of quad

Binary file not shown.

View file

@ -13,11 +13,8 @@ layout (location = 0) out vec4 outFragcolor;
struct Light {
vec4 position;
vec4 color;
vec3 color;
float radius;
float quadraticFalloff;
float linearFalloff;
float _pad;
};
layout (binding = 4) uniform UBO
@ -34,34 +31,44 @@ void main()
vec3 normal = texture(samplerNormal, inUV).rgb;
vec4 albedo = texture(samplerAlbedo, inUV);
#define lightCount 5
#define ambient 0.05
#define specularStrength 0.15
#define lightCount 6
#define ambient 0.0
// Ambient part
vec3 fragcolor = albedo.rgb * ambient;
vec3 viewVec = normalize(ubo.viewPos.xyz - fragPos);
for(int i = 0; i < lightCount; ++i)
{
// Vector to light
vec3 L = ubo.lights[i].position.xyz - fragPos;
// Distance from light to fragment position
float dist = length(ubo.lights[i].position.xyz - fragPos);
float dist = length(L);
if(dist < ubo.lights[i].radius)
// Viewer to fragment
vec3 V = ubo.viewPos.xyz - fragPos;
V = normalize(V);
//if(dist < ubo.lights[i].radius)
{
// Get vector from current light source to fragment position
vec3 lightVec = normalize(ubo.lights[i].position.xyz - fragPos);
// Diffuse part
vec3 diffuse = max(dot(normal, lightVec), 0.0) * albedo.rgb * ubo.lights[i].color.rgb;
// Specular part (specular texture part stored in albedo alpha channel)
vec3 halfVec = normalize(lightVec + viewVec);
vec3 specular = ubo.lights[i].color.rgb * pow(max(dot(normal, halfVec), 0.0), 16.0) * albedo.a * specularStrength;
// Attenuation with linearFalloff and quadraticFalloff falloff
float attenuation = 1.0 / (1.0 + ubo.lights[i].linearFalloff * dist + ubo.lights[i].quadraticFalloff * dist * dist);
fragcolor += (diffuse + specular) * attenuation;
}
// Light to fragment
L = normalize(L);
// Attenuation
float atten = ubo.lights[i].radius / (pow(dist, 2.0) + 1.0);
// Diffuse part
vec3 N = normalize(normal);
float NdotL = max(0.0, dot(N, L));
vec3 diff = ubo.lights[i].color * albedo.rgb * NdotL * atten;
// Specular part
// Specular map values are stored in alpha of albedo mrt
vec3 R = reflect(-L, N);
float NdotR = max(0.0, dot(R, V));
vec3 spec = ubo.lights[i].color * albedo.a * pow(NdotR, 16.0) * atten;
fragcolor += diff + spec;
}
}
outFragcolor = vec4(fragcolor, 1.0);

View file

@ -4,11 +4,13 @@
#extension GL_ARB_shading_language_420pack : enable
layout (binding = 1) uniform sampler2D samplerColor;
layout (binding = 2) uniform sampler2D samplerNormalMap;
layout (location = 0) in vec3 inNormal;
layout (location = 1) in vec2 inUV;
layout (location = 2) in vec3 inColor;
layout (location = 3) in vec3 inWorldPos;
layout (location = 4) in vec3 inTangent;
layout (location = 0) out vec4 outPosition;
layout (location = 1) out vec4 outNormal;
@ -17,6 +19,14 @@ layout (location = 2) out vec4 outAlbedo;
void main()
{
outPosition = vec4(inWorldPos, 1.0);
outNormal = vec4(inNormal, 1.0);
// Calculate normal in tangent space
vec3 N = normalize(inNormal);
vec3 T = normalize(inTangent);
vec3 B = cross(N, T);
mat3 TBN = mat3(T, B, N);
vec3 tnorm = TBN * normalize(texture(samplerNormalMap, inUV).xyz * 2.0 - vec3(1.0));
outNormal = vec4(tnorm, 1.0);
outAlbedo = texture(samplerColor, inUV);
}

Binary file not shown.

View file

@ -7,18 +7,21 @@ layout (location = 0) in vec4 inPos;
layout (location = 1) in vec2 inUV;
layout (location = 2) in vec3 inColor;
layout (location = 3) in vec3 inNormal;
layout (location = 4) in vec3 inTangent;
layout (binding = 0) uniform UBO
{
mat4 projection;
mat4 model;
mat4 view;
vec4 instancePos[3];
} ubo;
layout (location = 0) out vec3 outNormal;
layout (location = 1) out vec2 outUV;
layout (location = 2) out vec3 outColor;
layout (location = 3) out vec3 outWorldPos;
layout (location = 4) out vec3 outTangent;
out gl_PerVertex
{
@ -27,13 +30,14 @@ out gl_PerVertex
void main()
{
gl_Position = ubo.projection * ubo.view * ubo.model * inPos;
vec4 tmpPos = inPos + ubo.instancePos[gl_InstanceIndex];
gl_Position = ubo.projection * ubo.view * ubo.model * tmpPos;
outUV = inUV;
outUV.t = 1.0 - outUV.t;
// Vertex position in world space
vec4 tmpPos = inPos;
outWorldPos = vec3(ubo.model * tmpPos);
// GL to Vulkan coord space
outWorldPos.y = -outWorldPos.y;
@ -41,6 +45,7 @@ void main()
// Normal in world space
mat3 mNormal = transpose(inverse(mat3(ubo.model)));
outNormal = mNormal * normalize(inNormal);
outTangent = mNormal * normalize(inTangent);
// Currently just vertex color
outColor = inColor;

Binary file not shown.

View file

@ -1,5 +1,5 @@
/*
* Vulkan Example - Deferred shading multiple render targets (aka G-Buffer) example
* Vulkan Example - Deferred shading with multiple render targets (aka G-Buffer) example
*
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
*
@ -24,7 +24,7 @@
#define ENABLE_VALIDATION false
// Texture properties
#define TEX_DIM 1024
#define TEX_DIM 2048
#define TEX_FILTER VK_FILTER_LINEAR
// Offscreen frame buffer properties
@ -36,20 +36,29 @@ std::vector<vkMeshLoader::VertexLayout> vertexLayout =
vkMeshLoader::VERTEX_LAYOUT_POSITION,
vkMeshLoader::VERTEX_LAYOUT_UV,
vkMeshLoader::VERTEX_LAYOUT_COLOR,
vkMeshLoader::VERTEX_LAYOUT_NORMAL
vkMeshLoader::VERTEX_LAYOUT_NORMAL,
vkMeshLoader::VERTEX_LAYOUT_TANGENT
};
class VulkanExample : public VulkanExampleBase
{
public:
bool debugDisplay = true;
bool debugDisplay = false;
struct {
struct {
vkTools::VulkanTexture colorMap;
vkTools::VulkanTexture normalMap;
} model;
struct {
vkTools::VulkanTexture colorMap;
vkTools::VulkanTexture normalMap;
} floor;
} textures;
struct {
vkMeshLoader::MeshBuffer example;
vkMeshLoader::MeshBuffer model;
vkMeshLoader::MeshBuffer floor;
vkMeshLoader::MeshBuffer quad;
} meshes;
@ -63,19 +72,17 @@ public:
glm::mat4 projection;
glm::mat4 model;
glm::mat4 view;
glm::vec4 instancePos[3];
} uboVS, uboOffscreenVS;
struct Light {
glm::vec4 position;
glm::vec4 color;
glm::vec3 color;
float radius;
float quadraticFalloff;
float linearFalloff;
float _pad;
};
struct {
Light lights[5];
Light lights[6];
glm::vec4 viewPos;
} uboFragmentLights;
@ -97,7 +104,8 @@ public:
} pipelineLayouts;
struct {
VkDescriptorSet offscreen;
VkDescriptorSet model;
VkDescriptorSet floor;
} descriptorSets;
VkDescriptorSet descriptorSet;
@ -130,10 +138,15 @@ public:
{
zoom = -8.0f;
rotation = { 0.0f, 0.0f, 0.0f };
width = 1024;
height = 1024;
enableTextOverlay = true;
title = "Vulkan Example - Deferred shading";
title = "Vulkan Example - Deferred shading (2016 by Sascha Willems)";
camera.type = Camera::CameraType::firstperson;
camera.movementSpeed = 5.0f;
camera.rotationSpeed = 0.25f;
camera.position = { 2.15f, 0.3f, -8.75f };
camera.setRotation(glm::vec3(-0.75f, 12.5f, 0.0f));
camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f);
paused = true;
}
~VulkanExample()
@ -175,7 +188,8 @@ public:
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
// Meshes
vkMeshLoader::freeMeshBufferResources(device, &meshes.example);
vkMeshLoader::freeMeshBufferResources(device, &meshes.model);
vkMeshLoader::freeMeshBufferResources(device, &meshes.floor);
vkMeshLoader::freeMeshBufferResources(device, &meshes.quad);
// Uniform buffers
@ -187,7 +201,11 @@ public:
vkDestroyRenderPass(device, offScreenFrameBuf.renderPass, nullptr);
textureLoader->destroyTexture(textures.colorMap);
textureLoader->destroyTexture(textures.model.colorMap);
textureLoader->destroyTexture(textures.model.normalMap);
textureLoader->destroyTexture(textures.floor.colorMap);
textureLoader->destroyTexture(textures.floor.normalMap);
vkDestroySemaphore(device, offscreenSemaphore, nullptr);
}
@ -363,13 +381,13 @@ public:
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.pColorAttachments = colorReferences.data();
subpass.colorAttachmentCount = colorReferences.size();
subpass.colorAttachmentCount = static_cast<uint32_t>(colorReferences.size());
subpass.pDepthStencilAttachment = &depthReference;
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.pAttachments = attachmentDescs.data();
renderPassInfo.attachmentCount = attachmentDescs.size();
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachmentDescs.size());
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
@ -387,7 +405,7 @@ public:
fbufCreateInfo.pNext = NULL;
fbufCreateInfo.renderPass = offScreenFrameBuf.renderPass;
fbufCreateInfo.pAttachments = attachments.data();
fbufCreateInfo.attachmentCount = attachments.size();
fbufCreateInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
fbufCreateInfo.width = offScreenFrameBuf.width;
fbufCreateInfo.height = offScreenFrameBuf.height;
fbufCreateInfo.layers = 1;
@ -435,7 +453,7 @@ public:
renderPassBeginInfo.framebuffer = offScreenFrameBuf.frameBuffer;
renderPassBeginInfo.renderArea.extent.width = offScreenFrameBuf.width;
renderPassBeginInfo.renderArea.extent.height = offScreenFrameBuf.height;
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
renderPassBeginInfo.pClearValues = clearValues.data();
VK_CHECK_RESULT(vkBeginCommandBuffer(offScreenCmdBuffer, &cmdBufInfo));
@ -461,13 +479,21 @@ public:
VkRect2D scissor = vkTools::initializers::rect2D(offScreenFrameBuf.width, offScreenFrameBuf.height, 0, 0);
vkCmdSetScissor(offScreenCmdBuffer, 0, 1, &scissor);
vkCmdBindDescriptorSets(offScreenCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.offscreen, 0, 1, &descriptorSets.offscreen, 0, NULL);
vkCmdBindPipeline(offScreenCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.offscreen);
VkDeviceSize offsets[1] = { 0 };
vkCmdBindVertexBuffers(offScreenCmdBuffer, VERTEX_BUFFER_BIND_ID, 1, &meshes.example.vertices.buf, offsets);
vkCmdBindIndexBuffer(offScreenCmdBuffer, meshes.example.indices.buf, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(offScreenCmdBuffer, meshes.example.indexCount, 1, 0, 0, 0);
// Background
vkCmdBindDescriptorSets(offScreenCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.offscreen, 0, 1, &descriptorSets.floor, 0, NULL);
vkCmdBindVertexBuffers(offScreenCmdBuffer, VERTEX_BUFFER_BIND_ID, 1, &meshes.floor.vertices.buf, offsets);
vkCmdBindIndexBuffer(offScreenCmdBuffer, meshes.floor.indices.buf, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(offScreenCmdBuffer, meshes.floor.indexCount, 1, 0, 0, 0);
// Object
vkCmdBindDescriptorSets(offScreenCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.offscreen, 0, 1, &descriptorSets.model, 0, NULL);
vkCmdBindVertexBuffers(offScreenCmdBuffer, VERTEX_BUFFER_BIND_ID, 1, &meshes.model.vertices.buf, offsets);
vkCmdBindIndexBuffer(offScreenCmdBuffer, meshes.model.indices.buf, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(offScreenCmdBuffer, meshes.model.indexCount, 3, 0, 0, 0);
vkCmdEndRenderPass(offScreenCmdBuffer);
@ -487,10 +513,11 @@ public:
void loadTextures()
{
textureLoader->loadTexture(
getAssetPath() + "models/armor/colormap.ktx",
VK_FORMAT_BC3_UNORM_BLOCK,
&textures.colorMap);
textureLoader->loadTexture(getAssetPath() + "models/armor/colormap.ktx", VK_FORMAT_BC3_UNORM_BLOCK, &textures.model.colorMap);
textureLoader->loadTexture(getAssetPath() + "models/armor/normalmap.ktx", VK_FORMAT_BC3_UNORM_BLOCK, &textures.model.normalMap);
textureLoader->loadTexture(getAssetPath() + "textures/pattern_35_bc3.ktx", VK_FORMAT_BC3_UNORM_BLOCK, &textures.floor.colorMap);
textureLoader->loadTexture(getAssetPath() + "textures/pattern_35_normalmap_bc3.ktx", VK_FORMAT_BC3_UNORM_BLOCK, &textures.floor.normalMap);
}
void reBuildCommandBuffers()
@ -564,7 +591,13 @@ public:
void loadMeshes()
{
loadMesh(getAssetPath() + "models/armor/armor.dae", &meshes.example, vertexLayout, 1.0f);
loadMesh(getAssetPath() + "models/armor/armor.dae", &meshes.model, vertexLayout, 1.0f);
vkMeshLoader::MeshCreateInfo meshCreateInfo;
meshCreateInfo.scale = glm::vec3(2.0f);
meshCreateInfo.uvscale = glm::vec2(4.0f);
meshCreateInfo.center = glm::vec3(0.0f, 2.35f, 0.0f);
loadMesh(getAssetPath() + "models/plane.obj", &meshes.floor, vertexLayout, &meshCreateInfo);
}
void generateQuads()
@ -576,6 +609,7 @@ public:
float uv[2];
float col[3];
float normal[3];
float tangent[3];
};
std::vector<Vertex> vertexBuffer;
@ -614,7 +648,7 @@ public:
indexBuffer.push_back(i * 4 + index);
}
}
meshes.quad.indexCount = indexBuffer.size();
meshes.quad.indexCount = static_cast<uint32_t>(indexBuffer.size());
createBuffer(
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
@ -635,7 +669,7 @@ public:
VK_VERTEX_INPUT_RATE_VERTEX);
// Attribute descriptions
vertices.attributeDescriptions.resize(4);
vertices.attributeDescriptions.resize(5);
// Location 0: Position
vertices.attributeDescriptions[0] =
vkTools::initializers::vertexInputAttributeDescription(
@ -664,11 +698,18 @@ public:
3,
VK_FORMAT_R32G32B32_SFLOAT,
sizeof(float) * 8);
// Location 4: Tangent
vertices.attributeDescriptions[4] =
vkTools::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID,
4,
VK_FORMAT_R32G32B32_SFLOAT,
sizeof(float) * 11);
vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo();
vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size();
vertices.inputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertices.bindingDescriptions.size());
vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data();
vertices.inputState.vertexAttributeDescriptionCount = vertices.attributeDescriptions.size();
vertices.inputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertices.attributeDescriptions.size());
vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data();
}
@ -677,14 +718,14 @@ public:
std::vector<VkDescriptorPoolSize> poolSizes =
{
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 8),
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 8)
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 9)
};
VkDescriptorPoolCreateInfo descriptorPoolInfo =
vkTools::initializers::descriptorPoolCreateInfo(
poolSizes.size(),
static_cast<uint32_t>(poolSizes.size()),
poolSizes.data(),
2);
3);
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
}
@ -724,7 +765,7 @@ public:
VkDescriptorSetLayoutCreateInfo descriptorLayout =
vkTools::initializers::descriptorSetLayoutCreateInfo(
setLayoutBindings.data(),
setLayoutBindings.size());
static_cast<uint32_t>(setLayoutBindings.size()));
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout));
@ -741,6 +782,8 @@ public:
void setupDescriptorSet()
{
std::vector<VkWriteDescriptorSet> writeDescriptorSets;
// Textured quad descriptor set
VkDescriptorSetAllocateInfo allocInfo =
vkTools::initializers::descriptorSetAllocateInfo(
@ -769,8 +812,7 @@ public:
offScreenFrameBuf.albedo.view,
VK_IMAGE_LAYOUT_GENERAL);
std::vector<VkWriteDescriptorSet> writeDescriptorSets =
{
writeDescriptorSets = {
// Binding 0 : Vertex shader uniform buffer
vkTools::initializers::writeDescriptorSet(
descriptorSet,
@ -803,33 +845,59 @@ public:
&uniformData.fsLights.descriptor),
};
vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL);
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
// Offscreen (scene)
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.offscreen));
VkDescriptorImageInfo texDescriptorSceneColormap =
vkTools::initializers::descriptorImageInfo(
textures.colorMap.sampler,
textures.colorMap.view,
VK_IMAGE_LAYOUT_GENERAL);
std::vector<VkWriteDescriptorSet> offScreenWriteDescriptorSets =
// Model
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.model));
writeDescriptorSets =
{
// Binding 0: Vertex shader uniform buffer
vkTools::initializers::writeDescriptorSet(
descriptorSets.offscreen,
descriptorSets.model,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,
&uniformData.vsOffscreen.descriptor),
// Binding 1 : Scene color map
// Binding 1: Color map
vkTools::initializers::writeDescriptorSet(
descriptorSets.offscreen,
descriptorSets.model,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1,
&texDescriptorSceneColormap)
&textures.model.colorMap.descriptor),
// Binding 2: Normal map
vkTools::initializers::writeDescriptorSet(
descriptorSets.model,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
2,
&textures.model.normalMap.descriptor)
};
vkUpdateDescriptorSets(device, offScreenWriteDescriptorSets.size(), offScreenWriteDescriptorSets.data(), 0, NULL);
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
// Backbround
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSets.floor));
writeDescriptorSets =
{
// Binding 0: Vertex shader uniform buffer
vkTools::initializers::writeDescriptorSet(
descriptorSets.floor,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,
&uniformData.vsOffscreen.descriptor),
// Binding 1: Color map
vkTools::initializers::writeDescriptorSet(
descriptorSets.floor,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1,
&textures.floor.colorMap.descriptor),
// Binding 2: Normal map
vkTools::initializers::writeDescriptorSet(
descriptorSets.floor,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
2,
&textures.floor.normalMap.descriptor)
};
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
}
void preparePipelines()
@ -878,7 +946,7 @@ public:
VkPipelineDynamicStateCreateInfo dynamicState =
vkTools::initializers::pipelineDynamicStateCreateInfo(
dynamicStateEnables.data(),
dynamicStateEnables.size(),
static_cast<uint32_t>(dynamicStateEnables.size()),
0);
// Final fullscreen pass pipeline
@ -901,7 +969,7 @@ public:
pipelineCreateInfo.pViewportState = &viewportState;
pipelineCreateInfo.pDepthStencilState = &depthStencilState;
pipelineCreateInfo.pDynamicState = &dynamicState;
pipelineCreateInfo.stageCount = shaderStages.size();
pipelineCreateInfo.stageCount = static_cast<uint32_t>(shaderStages.size());
pipelineCreateInfo.pStages = shaderStages.data();
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.deferred));
@ -930,7 +998,7 @@ public:
vkTools::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE)
};
colorBlendState.attachmentCount = blendAttachmentStates.size();
colorBlendState.attachmentCount = static_cast<uint32_t>(blendAttachmentStates.size());
colorBlendState.pAttachments = blendAttachmentStates.data();
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.offscreen));
@ -969,6 +1037,11 @@ public:
&uniformData.fsLights.memory,
&uniformData.fsLights.descriptor);
// Init some values
uboOffscreenVS.instancePos[0] = glm::vec4(0.0f);
uboOffscreenVS.instancePos[1] = glm::vec4(-4.0f, 0.0, -4.0f, 0.0f);
uboOffscreenVS.instancePos[2] = glm::vec4(4.0f, 0.0, -4.0f, 0.0f);
// Update
updateUniformBuffersScreen();
updateUniformBufferDeferredMatrices();
@ -1004,6 +1077,10 @@ public:
uboOffscreenVS.model = glm::rotate(uboOffscreenVS.model, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
uboOffscreenVS.model = glm::rotate(uboOffscreenVS.model, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
uboOffscreenVS.projection = camera.matrices.perspective;
uboOffscreenVS.view = camera.matrices.view;
uboOffscreenVS.model = glm::mat4();
uint8_t *pData;
VK_CHECK_RESULT(vkMapMemory(device, uniformData.vsOffscreen.memory, 0, sizeof(uboOffscreenVS), 0, (void **)&pData));
memcpy(pData, &uboOffscreenVS, sizeof(uboOffscreenVS));
@ -1013,39 +1090,48 @@ public:
// Update fragment shader light position uniform block
void updateUniformBufferDeferredLights()
{
// White light from above
uboFragmentLights.lights[0].position = glm::vec4(0.0f, 3.0f, 1.0f, 0.0f);
uboFragmentLights.lights[0].color = glm::vec4(1.5f);
uboFragmentLights.lights[0].radius = 15.0f;
uboFragmentLights.lights[0].linearFalloff = 0.3f;
uboFragmentLights.lights[0].quadraticFalloff = 0.4f;
// Red light
// White
uboFragmentLights.lights[0].position = glm::vec4(0.0f, 0.0f, 1.0f, 0.0f);
uboFragmentLights.lights[0].color = glm::vec3(1.5f);
uboFragmentLights.lights[0].radius = 15.0f * 0.25f;
// Red
uboFragmentLights.lights[1].position = glm::vec4(-2.0f, 0.0f, 0.0f, 0.0f);
uboFragmentLights.lights[1].color = glm::vec4(1.5f, 0.0f, 0.0f, 0.0f);
uboFragmentLights.lights[1].color = glm::vec3(1.0f, 0.0f, 0.0f);
uboFragmentLights.lights[1].radius = 15.0f;
uboFragmentLights.lights[1].linearFalloff = 0.4f;
uboFragmentLights.lights[1].quadraticFalloff = 0.3f;
// Blue light
// Blue
uboFragmentLights.lights[2].position = glm::vec4(2.0f, 1.0f, 0.0f, 0.0f);
uboFragmentLights.lights[2].color = glm::vec4(0.0f, 0.0f, 2.5f, 0.0f);
uboFragmentLights.lights[2].radius = 10.0f;
uboFragmentLights.lights[2].linearFalloff = 0.45f;
uboFragmentLights.lights[2].quadraticFalloff = 0.35f;
// Belt glow
uboFragmentLights.lights[3].position = glm::vec4(0.0f, 0.7f, 0.5f, 0.0f);
uboFragmentLights.lights[3].color = glm::vec4(2.5f, 2.5f, 0.0f, 0.0f);
uboFragmentLights.lights[3].radius = 5.0f;
uboFragmentLights.lights[3].linearFalloff = 8.0f;
uboFragmentLights.lights[3].quadraticFalloff = 6.0f;
// Green light
uboFragmentLights.lights[4].position = glm::vec4(3.0f, 2.0f, 1.0f, 0.0f);
uboFragmentLights.lights[4].color = glm::vec4(0.0f, 1.5f, 0.0f, 0.0f);
uboFragmentLights.lights[4].radius = 10.0f;
uboFragmentLights.lights[4].linearFalloff = 0.8f;
uboFragmentLights.lights[4].quadraticFalloff = 0.6f;
uboFragmentLights.lights[2].color = glm::vec3(0.0f, 0.0f, 2.5f);
uboFragmentLights.lights[2].radius = 5.0f;
// Yellow
uboFragmentLights.lights[3].position = glm::vec4(0.0f, 0.9f, 0.5f, 0.0f);
uboFragmentLights.lights[3].color = glm::vec3(1.0f, 1.0f, 0.0f);
uboFragmentLights.lights[3].radius = 2.0f;
// Green
uboFragmentLights.lights[4].position = glm::vec4(0.0f, 0.5f, 0.0f, 0.0f);
uboFragmentLights.lights[4].color = glm::vec3(0.0f, 1.0f, 0.2f);
uboFragmentLights.lights[4].radius = 5.0f;
// Yellow
uboFragmentLights.lights[5].position = glm::vec4(0.0f, 1.0f, 0.0f, 0.0f);
uboFragmentLights.lights[5].color = glm::vec3(1.0f, 0.7f, 0.3f);
uboFragmentLights.lights[5].radius = 25.0f;
uboFragmentLights.lights[0].position.x = sin(glm::radians(360.0f * timer)) * 5.0f;
uboFragmentLights.lights[0].position.z = cos(glm::radians(360.0f * timer)) * 5.0f;
uboFragmentLights.lights[1].position.x = -4.0f + sin(glm::radians(360.0f * timer) + 45.0f) * 2.0f;
uboFragmentLights.lights[1].position.z = 0.0f + cos(glm::radians(360.0f * timer) + 45.0f) * 2.0f;
uboFragmentLights.lights[2].position.x = 4.0f + sin(glm::radians(360.0f * timer)) * 2.0f;
uboFragmentLights.lights[2].position.z = 0.0f + cos(glm::radians(360.0f * timer)) * 2.0f;
uboFragmentLights.lights[4].position.x = 0.0f + sin(glm::radians(360.0f * timer + 90.0f)) * 5.0f;
uboFragmentLights.lights[4].position.z = 0.0f - cos(glm::radians(360.0f * timer + 45.0f)) * 5.0f;
uboFragmentLights.lights[5].position.x = 0.0f + sin(glm::radians(-360.0f * timer + 135.0f)) * 10.0f;
uboFragmentLights.lights[5].position.z = 0.0f - cos(glm::radians(-360.0f * timer - 45.0f)) * 10.0f;
// Current view position
uboFragmentLights.viewPos = glm::vec4(0.0f, 0.0f, -zoom, 0.0f);
uboFragmentLights.viewPos = glm::vec4(camera.position, 0.0f) * glm::vec4(-1.0f, 1.0f, -1.0f, 1.0f);
uint8_t *pData;
VK_CHECK_RESULT(vkMapMemory(device, uniformData.fsLights.memory, 0, sizeof(uboFragmentLights), 0, (void **)&pData));
@ -1117,6 +1203,7 @@ public:
if (!prepared)
return;
draw();
updateUniformBufferDeferredLights();
}
virtual void viewChanged()
@ -1135,7 +1222,7 @@ public:
{
switch (keyCode)
{
case 0x44:
case 0x70:
case GAMEPAD_BUTTON_A:
toggleDebugDisplay();
updateTextOverlay();
@ -1146,78 +1233,19 @@ public:
virtual void getOverlayText(VulkanTextOverlay *textOverlay)
{
#if defined(__ANDROID__)
textOverlay->addText("Press \"Button A\" to toggle render targets", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
textOverlay->addText("Press \"Button A\" to toggle debug display", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
#else
textOverlay->addText("Press \"d\" to toggle render targets", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
textOverlay->addText("Press \"F1\" to toggle debug display", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
#endif
// Render targets
if (debugDisplay)
{
textOverlay->addText("World Position", (float)width * 0.25f, (float)height * 0.5f - 25.0f, VulkanTextOverlay::alignCenter);
textOverlay->addText("World normals", (float)width * 0.75f, (float)height * 0.5f - 25.0f, VulkanTextOverlay::alignCenter);
textOverlay->addText("Color", (float)width * 0.25f, (float)height - 25.0f, VulkanTextOverlay::alignCenter);
textOverlay->addText("World space position", (float)width * 0.25f, (float)height * 0.5f - 25.0f, VulkanTextOverlay::alignCenter);
textOverlay->addText("World space normals", (float)width * 0.75f, (float)height * 0.5f - 25.0f, VulkanTextOverlay::alignCenter);
textOverlay->addText("Albedo", (float)width * 0.25f, (float)height - 25.0f, VulkanTextOverlay::alignCenter);
textOverlay->addText("Final image", (float)width * 0.75f, (float)height - 25.0f, VulkanTextOverlay::alignCenter);
}
}
};
VulkanExample *vulkanExample;
#if defined(_WIN32)
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (vulkanExample != NULL)
{
vulkanExample->handleMessages(hWnd, uMsg, wParam, lParam);
}
return (DefWindowProc(hWnd, uMsg, wParam, lParam));
}
#elif defined(__linux__) && !defined(__ANDROID__)
static void handleEvent(const xcb_generic_event_t *event)
{
if (vulkanExample != NULL)
{
vulkanExample->handleEvent(event);
}
}
#endif
// Main entry point
#if defined(_WIN32)
// Windows entry point
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow)
#elif defined(__ANDROID__)
// Android entry point
void android_main(android_app* state)
#elif defined(__linux__)
// Linux entry point
int main(const int argc, const char *argv[])
#endif
{
#if defined(__ANDROID__)
// Removing this may cause the compiler to omit the main entry point
// which would make the application crash at start
app_dummy();
#endif
vulkanExample = new VulkanExample();
#if defined(_WIN32)
vulkanExample->setupWindow(hInstance, WndProc);
#elif defined(__ANDROID__)
// Attach vulkan example to global android application state
state->userData = vulkanExample;
state->onAppCmd = VulkanExample::handleAppCommand;
state->onInputEvent = VulkanExample::handleAppInput;
vulkanExample->androidApp = state;
#elif defined(__linux__)
vulkanExample->setupWindow();
#endif
#if !defined(__ANDROID__)
vulkanExample->initSwapchain();
vulkanExample->prepare();
#endif
vulkanExample->renderLoop();
delete(vulkanExample);
#if !defined(__ANDROID__)
return 0;
#endif
}
VULKAN_EXAMPLE_MAIN()

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB