mirror of
https://github.com/bailwillharr/engine.git
synced 2024-09-21 04:51:18 +00:00
Get shadow mapping mostly working
This commit is contained in:
parent
dcd71d3a14
commit
389c979f2f
@ -123,6 +123,7 @@ struct PipelineInfo {
|
||||
bool alpha_blending;
|
||||
bool write_z;
|
||||
bool line_primitives; // false for triangles, true for lines
|
||||
bool depth_attachment_only; // false 99% of the time
|
||||
std::vector<const DescriptorSetLayout*> descriptor_set_layouts;
|
||||
};
|
||||
|
||||
|
@ -31,6 +31,10 @@ class GFXDevice {
|
||||
- draw_buffer is invalid after this function has been called. */
|
||||
void FinishRender(gfx::DrawBuffer* draw_buffer);
|
||||
|
||||
gfx::Image* CreateShadowmapImage();
|
||||
gfx::DrawBuffer* BeginShadowmapRender(gfx::Image* image);
|
||||
void FinishShadowmapRender(gfx::DrawBuffer* draw_buffer, gfx::Image* image);
|
||||
|
||||
/* - draw_buffer MUST be a valid pointer returned by BeginRender()
|
||||
- pipeline MUST be a valid pointer returned by CreatePipeline() */
|
||||
void CmdBindPipeline(gfx::DrawBuffer* draw_buffer,
|
||||
|
@ -112,6 +112,9 @@ class Renderer : private ApplicationComponent {
|
||||
|
||||
gfx::Image* shadow_map = nullptr;
|
||||
const gfx::Sampler* shadow_map_sampler = nullptr;
|
||||
const gfx::Pipeline* shadow_pipeline = nullptr;
|
||||
|
||||
bool rendering_started = false;
|
||||
|
||||
void DrawRenderList(gfx::DrawBuffer* draw_buffer, const RenderList& render_list);
|
||||
};
|
||||
|
@ -51,7 +51,7 @@ void main() {
|
||||
const vec3 N = GetNormal();
|
||||
|
||||
const vec3 V = normalize(fragViewPosTangentSpace - fragPosTangentSpace);
|
||||
const vec3 L = normalize(fragLightPosTangentSpace);
|
||||
const vec3 L = normalize(fragLightPosTangentSpace - fragPosTangentSpace);
|
||||
//const vec3 L = normalize(vec3(5.0, 0.0, 3.0));
|
||||
const vec3 H = normalize(V + L);
|
||||
|
||||
@ -80,16 +80,18 @@ void main() {
|
||||
|
||||
vec3 lighting = brdf * light_colour * L_dot_N;
|
||||
|
||||
vec3 ambient_light = vec3(0.09082, 0.13281, 0.18164);
|
||||
lighting += mix(ambient_light, texture(globalSetSkybox, R).rgb, metallic) * ao * diffuse_brdf; // this is NOT physically-based, it just looks cool
|
||||
|
||||
// perform perspective divide
|
||||
vec3 projCoords = fragPosLightSpace.xyz;
|
||||
// find if fragment is in shadow
|
||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
projCoords.x = projCoords.x * 0.5 + 0.5;
|
||||
projCoords.y = projCoords.y * 0.5 + 0.5;
|
||||
float closestDepth = texture(globalSetShadowmap, projCoords.xy).r;
|
||||
float currentDepth = projCoords.z;
|
||||
float shadow = currentDepth > closestDepth ? 1.0 : 0.0;
|
||||
float shadow = currentDepth > closestDepth ? 0.0 : 1.0;
|
||||
lighting *= shadow;
|
||||
|
||||
vec3 ambient_light = vec3(0.09082, 0.13281, 0.18164);
|
||||
lighting += mix(ambient_light, texture(globalSetSkybox, R).rgb, metallic) * ao * diffuse_brdf; // this is NOT physically-based, it just looks cool
|
||||
|
||||
outColor = vec4(min(emission + lighting, 1.0), 1.0);
|
||||
//outColor = vec4(shadow, 0.0, 0.0, 1.0);
|
||||
//outColor = vec4(vec3(shadow), 1.0);
|
||||
}
|
||||
|
@ -39,7 +39,8 @@ void main() {
|
||||
fragUV = inUV;
|
||||
fragPosTangentSpace = worldToTangentSpace * vec3(worldPosition);
|
||||
fragViewPosTangentSpace = worldToTangentSpace * vec3(inverse(frameSetUniformBuffer.view) * vec4(0.0, 0.0, 0.0, 1.0));
|
||||
fragLightPosTangentSpace = worldToTangentSpace * vec3(-0.4278,0.7923,0.43502);
|
||||
//fragLightPosTangentSpace = worldToTangentSpace * vec3(-0.4278,0.7923,0.43502);
|
||||
fragLightPosTangentSpace = worldToTangentSpace * vec3(10.0, 0.0, 10.0);
|
||||
|
||||
fragNormWorldSpace = N;
|
||||
fragViewPosWorldSpace = vec3(inverse(frameSetUniformBuffer.view) * vec4(0.0, 0.0, 0.0, 1.0));
|
||||
|
5
res/engine/shaders/shadow.frag
Normal file
5
res/engine/shaders/shadow.frag
Normal file
@ -0,0 +1,5 @@
|
||||
#version 450
|
||||
|
||||
void main() {
|
||||
// empty fragment shader
|
||||
}
|
17
res/engine/shaders/shadow.vert
Normal file
17
res/engine/shaders/shadow.vert
Normal file
@ -0,0 +1,17 @@
|
||||
#version 450
|
||||
|
||||
layout(set = 0, binding = 0) uniform GlobalSetUniformBuffer {
|
||||
mat4 proj;
|
||||
mat4 lightSpaceMatrix;
|
||||
} globalSetUniformBuffer;
|
||||
|
||||
layout( push_constant ) uniform Constants {
|
||||
mat4 model;
|
||||
} constants;
|
||||
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
|
||||
void main() {
|
||||
gl_Position = globalSetUniformBuffer.lightSpaceMatrix * constants.model * vec4(inPosition, 1.0);
|
||||
//gl_Position.y *= -1.0;
|
||||
}
|
@ -72,6 +72,8 @@ static constexpr uint32_t FRAMES_IN_FLIGHT = 2; // This improved FPS by 5x
|
||||
static constexpr size_t PUSH_CONSTANT_MAX_SIZE = 128; // bytes
|
||||
static constexpr VkIndexType INDEX_TYPE = VK_INDEX_TYPE_UINT32;
|
||||
|
||||
static constexpr int kShadowmapSize = 2048;
|
||||
|
||||
// structures and enums
|
||||
|
||||
struct FrameData {
|
||||
@ -677,7 +679,7 @@ gfx::DrawBuffer* GFXDevice::BeginRender()
|
||||
// ownership transfer isn't needed since the data isn't accessed it's just overwritten
|
||||
|
||||
{
|
||||
// copy stagings buffers to GPU buffer
|
||||
// copy staging buffers to GPU buffers
|
||||
for (gfx::UniformBuffer* uniformBuffer : pimpl->write_queues[currentFrameIndex].uniform_buffer_writes) {
|
||||
VkBufferCopy copyRegion{};
|
||||
copyRegion.srcOffset = 0;
|
||||
@ -889,7 +891,7 @@ gfx::DrawBuffer* GFXDevice::BeginRender()
|
||||
pimpl->write_queues[currentFrameIndex].uniform_buffer_writes.clear();
|
||||
|
||||
// hand command buffer over to caller
|
||||
gfx::DrawBuffer* drawBuffer = new gfx::DrawBuffer;
|
||||
gfx::DrawBuffer* drawBuffer = new gfx::DrawBuffer; // heap allocation every frame but it's only 72 bytes
|
||||
drawBuffer->frameData = frameData;
|
||||
drawBuffer->currentFrameIndex = currentFrameIndex;
|
||||
drawBuffer->imageIndex = swapchainImageIndex;
|
||||
@ -1006,6 +1008,222 @@ void GFXDevice::FinishRender(gfx::DrawBuffer* drawBuffer)
|
||||
delete drawBuffer;
|
||||
}
|
||||
|
||||
gfx::Image* GFXDevice::CreateShadowmapImage()
|
||||
{
|
||||
if (pimpl->FRAMECOUNT != 0) abort();
|
||||
|
||||
gfx::Image* out = new gfx::Image{};
|
||||
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageInfo.flags = 0;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.format = pimpl->swapchain.depthStencilFormat;
|
||||
imageInfo.extent.width = kShadowmapSize;
|
||||
imageInfo.extent.height = kShadowmapSize;
|
||||
imageInfo.extent.depth = 1;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.arrayLayers = 1;
|
||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
VmaAllocationCreateInfo allocCreateInfo{};
|
||||
allocCreateInfo.flags = 0;
|
||||
allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||
allocCreateInfo.priority = 0.5f;
|
||||
|
||||
VKCHECK(vmaCreateImage(pimpl->allocator, &imageInfo, &allocCreateInfo, &out->image, &out->allocation, nullptr));
|
||||
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = out->image;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = pimpl->swapchain.depthStencilFormat;
|
||||
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||
viewInfo.subresourceRange.levelCount = 1;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
|
||||
VKCHECK(vkCreateImageView(pimpl->device.device, &viewInfo, nullptr, &out->view));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
gfx::DrawBuffer* GFXDevice::BeginShadowmapRender(gfx::Image* image)
|
||||
{
|
||||
assert(image != nullptr);
|
||||
if (pimpl->FRAMECOUNT != 0) throw std::runtime_error("Can only create shadowmap before proper rendering begins.");
|
||||
|
||||
VkResult res;
|
||||
|
||||
/* record command buffer */
|
||||
res = vkResetCommandPool(pimpl->device.device, pimpl->graphicsCommandPool, 0);
|
||||
VKCHECK(res);
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||
.pInheritanceInfo = nullptr // ignored
|
||||
};
|
||||
res = vkBeginCommandBuffer(pimpl->frameData[0].drawBuf, &beginInfo);
|
||||
VKCHECK(res);
|
||||
|
||||
{
|
||||
// make the depth image an attachment layout
|
||||
VkImageMemoryBarrier2 barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
|
||||
barrier.pNext = nullptr;
|
||||
barrier.srcStageMask = VK_PIPELINE_STAGE_2_NONE;
|
||||
barrier.dstStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT;
|
||||
barrier.srcAccessMask = VK_ACCESS_2_NONE;
|
||||
barrier.dstAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
barrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
|
||||
barrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
|
||||
barrier.image = image->image;
|
||||
VkImageSubresourceRange range{};
|
||||
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
range.baseMipLevel = 0;
|
||||
range.levelCount = 1;
|
||||
range.baseArrayLayer = 0;
|
||||
range.layerCount = 1;
|
||||
barrier.subresourceRange = range;
|
||||
|
||||
VkDependencyInfo imageDependencyInfo{};
|
||||
imageDependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
|
||||
imageDependencyInfo.imageMemoryBarrierCount = 1;
|
||||
imageDependencyInfo.pImageMemoryBarriers = &barrier;
|
||||
vkCmdPipelineBarrier2(pimpl->frameData[0].drawBuf, &imageDependencyInfo);
|
||||
|
||||
VkClearValue clearValue{};
|
||||
clearValue.depthStencil.depth = 1.0f;
|
||||
|
||||
VkRenderingAttachmentInfo depthAttachment{};
|
||||
depthAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
|
||||
depthAttachment.pNext = nullptr;
|
||||
depthAttachment.imageView = image->view;
|
||||
depthAttachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
depthAttachment.resolveMode = VK_RESOLVE_MODE_NONE;
|
||||
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
depthAttachment.clearValue = clearValue;
|
||||
|
||||
VkRenderingInfo renderingInfo{};
|
||||
renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
|
||||
renderingInfo.pNext = nullptr;
|
||||
renderingInfo.flags = 0;
|
||||
renderingInfo.renderArea = VkRect2D{VkOffset2D{0, 0}, VkExtent2D{kShadowmapSize, kShadowmapSize}};
|
||||
renderingInfo.layerCount = 1;
|
||||
renderingInfo.viewMask = 0;
|
||||
renderingInfo.colorAttachmentCount = 0;
|
||||
renderingInfo.pColorAttachments = nullptr; // no color attachment for this render pass
|
||||
renderingInfo.pDepthAttachment = &depthAttachment;
|
||||
renderingInfo.pStencilAttachment = nullptr;
|
||||
vkCmdBeginRendering(pimpl->frameData[0].drawBuf, &renderingInfo);
|
||||
|
||||
VkViewport viewport{};
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = (float)kShadowmapSize;
|
||||
viewport.height = (float)kShadowmapSize;
|
||||
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(pimpl->frameData[0].drawBuf, 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissor{};
|
||||
scissor.offset = {0, 0};
|
||||
scissor.extent = { kShadowmapSize, kShadowmapSize };
|
||||
vkCmdSetScissor(pimpl->frameData[0].drawBuf, 0, 1, &scissor);
|
||||
|
||||
// Depth bias (and slope) are used to avoid shadowing artifacts
|
||||
// Constant depth bias factor (always applied)
|
||||
constexpr float depthBiasConstant = 1.25f;
|
||||
// Slope depth bias factor, applied depending on polygon's slope
|
||||
constexpr float depthBiasSlope = 1.75f;
|
||||
// Set depth bias (aka "Polygon offset")
|
||||
// Required to avoid shadow mapping artifacts
|
||||
vkCmdSetDepthBias(
|
||||
pimpl->frameData[0].drawBuf,
|
||||
depthBiasConstant,
|
||||
0.0f,
|
||||
depthBiasSlope);
|
||||
|
||||
}
|
||||
|
||||
// hand command buffer over to caller
|
||||
gfx::DrawBuffer* drawBuffer = new gfx::DrawBuffer; // heap allocation every frame but it's only 72 bytes
|
||||
drawBuffer->frameData = pimpl->frameData[0];
|
||||
drawBuffer->currentFrameIndex = 0;
|
||||
drawBuffer->imageIndex = std::numeric_limits<uint32_t>::max(); // meaningless here
|
||||
return drawBuffer;
|
||||
}
|
||||
|
||||
void GFXDevice::FinishShadowmapRender(gfx::DrawBuffer* draw_buffer, gfx::Image* image)
|
||||
{
|
||||
assert(draw_buffer != nullptr);
|
||||
|
||||
VkResult res;
|
||||
|
||||
vkCmdEndRendering(draw_buffer->frameData.drawBuf);
|
||||
|
||||
// make the depth image readable by a sampler
|
||||
VkImageMemoryBarrier2 barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
|
||||
barrier.pNext = nullptr;
|
||||
barrier.srcStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT;
|
||||
barrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
|
||||
barrier.srcAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT;
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
barrier.srcQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
|
||||
barrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
|
||||
barrier.image = image->image;
|
||||
VkImageSubresourceRange range{};
|
||||
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
range.baseMipLevel = 0;
|
||||
range.levelCount = 1;
|
||||
range.baseArrayLayer = 0;
|
||||
range.layerCount = 1;
|
||||
barrier.subresourceRange = range;
|
||||
|
||||
VkDependencyInfo imageDependencyInfo{};
|
||||
imageDependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
|
||||
imageDependencyInfo.imageMemoryBarrierCount = 1;
|
||||
imageDependencyInfo.pImageMemoryBarriers = &barrier;
|
||||
vkCmdPipelineBarrier2(draw_buffer->frameData.drawBuf, &imageDependencyInfo);
|
||||
|
||||
res = vkEndCommandBuffer(draw_buffer->frameData.drawBuf);
|
||||
VKCHECK(res);
|
||||
|
||||
// SUBMIT
|
||||
|
||||
VkSubmitInfo submitInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.pNext = nullptr,
|
||||
.waitSemaphoreCount = 0,
|
||||
.pWaitSemaphores = nullptr,
|
||||
.pWaitDstStageMask = nullptr,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &draw_buffer->frameData.drawBuf,
|
||||
.signalSemaphoreCount = 0,
|
||||
.pSignalSemaphores = nullptr,
|
||||
};
|
||||
res = vkQueueSubmit(pimpl->device.queues.drawQueues[0], 1, &submitInfo, VK_NULL_HANDLE);
|
||||
VKCHECK(res);
|
||||
|
||||
vkQueueWaitIdle(pimpl->device.queues.drawQueues[0]);
|
||||
|
||||
delete draw_buffer;
|
||||
}
|
||||
|
||||
void GFXDevice::CmdBindPipeline(gfx::DrawBuffer* drawBuffer, const gfx::Pipeline* pipeline)
|
||||
{
|
||||
assert(drawBuffer != nullptr);
|
||||
@ -1124,6 +1342,7 @@ gfx::Pipeline* GFXDevice::CreatePipeline(const gfx::PipelineInfo& info)
|
||||
inputAssembly.topology = info.line_primitives ? VK_PRIMITIVE_TOPOLOGY_LINE_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
inputAssembly.primitiveRestartEnable = VK_FALSE;
|
||||
|
||||
#if 0
|
||||
VkViewport viewport{};
|
||||
if (flip_viewport) {
|
||||
viewport.x = 0.0f;
|
||||
@ -1143,6 +1362,7 @@ gfx::Pipeline* GFXDevice::CreatePipeline(const gfx::PipelineInfo& info)
|
||||
VkRect2D scissor{};
|
||||
scissor.offset = {0, 0};
|
||||
scissor.extent = pimpl->swapchain.extent;
|
||||
#endif
|
||||
|
||||
// Dynamic states removes the need to re-create pipelines whenever the window
|
||||
// size changes
|
||||
@ -1156,9 +1376,9 @@ gfx::Pipeline* GFXDevice::CreatePipeline(const gfx::PipelineInfo& info)
|
||||
VkPipelineViewportStateCreateInfo viewportState{};
|
||||
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
viewportState.viewportCount = 1;
|
||||
viewportState.pViewports = &viewport;
|
||||
viewportState.pViewports = nullptr;
|
||||
viewportState.scissorCount = 1;
|
||||
viewportState.pScissors = &scissor;
|
||||
viewportState.pScissors = nullptr;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rasterizer{};
|
||||
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
@ -1246,7 +1466,7 @@ gfx::Pipeline* GFXDevice::CreatePipeline(const gfx::PipelineInfo& info)
|
||||
createInfo.pStages = shaderStages;
|
||||
createInfo.pVertexInputState = &vertexInputInfo;
|
||||
createInfo.pInputAssemblyState = &inputAssembly;
|
||||
createInfo.pViewportState = &viewportState; // TODO: maybe this isn't needed?
|
||||
createInfo.pViewportState = &viewportState;
|
||||
createInfo.pRasterizationState = &rasterizer;
|
||||
createInfo.pMultisampleState = &multisampling;
|
||||
createInfo.pDepthStencilState = &depthStencil;
|
||||
@ -1260,8 +1480,14 @@ gfx::Pipeline* GFXDevice::CreatePipeline(const gfx::PipelineInfo& info)
|
||||
|
||||
VkPipelineRenderingCreateInfo renderingInfo{};
|
||||
renderingInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
|
||||
if (info.depth_attachment_only) {
|
||||
renderingInfo.colorAttachmentCount = 0;
|
||||
renderingInfo.pColorAttachmentFormats = nullptr;
|
||||
}
|
||||
else {
|
||||
renderingInfo.colorAttachmentCount = 1;
|
||||
renderingInfo.pColorAttachmentFormats = &pimpl->swapchain.surfaceFormat.format;
|
||||
}
|
||||
renderingInfo.depthAttachmentFormat = pimpl->swapchain.depthStencilFormat;
|
||||
|
||||
createInfo.pNext = &renderingInfo;
|
||||
|
@ -32,10 +32,12 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
|
||||
}
|
||||
global_uniform.layout = device_->CreateDescriptorSetLayout(globalSetBindings);
|
||||
global_uniform.set = device_->AllocateDescriptorSet(global_uniform.layout);
|
||||
global_uniform.uniform_buffer_data.data.proj = glm::mat4{1.0f};
|
||||
const glm::vec3 light_location{ -0.4278, 0.7923, 0.43502 };
|
||||
const glm::mat4 light_proj = glm::orthoRH_ZO(-32.0f, 32.0f, -32.0f, 32.0f, -100.0f, 100.0f);
|
||||
//const glm::vec3 light_location = glm::vec3{-0.4278, 0.7923, 0.43502} * 10.0f;
|
||||
const glm::vec3 light_location = glm::vec3{ 10.0f, 0.0f, 10.0f };
|
||||
//const glm::mat4 light_proj = glm::orthoRH_ZO(-10.0f, 10.0f, -10.0f, 10.0f, 1.0f, 50.0f);
|
||||
const glm::mat4 light_proj = glm::perspectiveFovRH_ZO(glm::radians(90.0f), 1.0f, 1.0f, 5.0f, 50.0f);
|
||||
const glm::mat4 light_view = glm::lookAtRH(light_location, glm::vec3{0.0f, 0.0f, 0.0f}, glm::vec3{0.0f, 0.0f, 1.0f});
|
||||
global_uniform.uniform_buffer_data.data.proj = light_proj;
|
||||
global_uniform.uniform_buffer_data.data.lightSpaceMatrix = light_proj * light_view;
|
||||
global_uniform.uniform_buffer = device_->CreateUniformBuffer(sizeof(global_uniform.uniform_buffer_data), &global_uniform.uniform_buffer_data);
|
||||
device_->UpdateDescriptorUniformBuffer(global_uniform.set, 0, global_uniform.uniform_buffer, 0, sizeof(global_uniform.uniform_buffer_data));
|
||||
@ -50,7 +52,7 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
|
||||
}
|
||||
frame_uniform.layout = device_->CreateDescriptorSetLayout(frameSetBindings);
|
||||
frame_uniform.set = device_->AllocateDescriptorSet(frame_uniform.layout);
|
||||
frame_uniform.uniform_buffer_data.data = glm::mat4{1.0f};
|
||||
frame_uniform.uniform_buffer_data.data = light_view;
|
||||
frame_uniform.uniform_buffer = device_->CreateUniformBuffer(sizeof(frame_uniform.uniform_buffer_data), &frame_uniform.uniform_buffer_data);
|
||||
device_->UpdateDescriptorUniformBuffer(frame_uniform.set, 0, frame_uniform.uniform_buffer, 0, sizeof(frame_uniform.uniform_buffer_data));
|
||||
|
||||
@ -188,28 +190,26 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
|
||||
|
||||
skybox_buffer = device_->CreateBuffer(gfx::BufferType::kVertex, v.size() * sizeof(glm::vec3), v.data());
|
||||
}
|
||||
|
||||
// shadow mapping...
|
||||
{
|
||||
int w{}, h{};
|
||||
auto shadowmap_image = util::ReadImageFile(GetResourcePath("textures/shadow_map.png"), w, h);
|
||||
shadow_map = device_->CreateImage(w, h, gfx::ImageFormat::kLinear, shadowmap_image->data());
|
||||
gfx::SamplerInfo sampler_info{};
|
||||
sampler_info.magnify = gfx::Filter::kLinear;
|
||||
sampler_info.minify = gfx::Filter::kLinear;
|
||||
sampler_info.mipmap = gfx::Filter::kLinear; // trilinear is apparently good for shadow maps
|
||||
sampler_info.wrap_u = gfx::WrapMode::kClampToEdge;
|
||||
sampler_info.wrap_v = gfx::WrapMode::kClampToEdge;
|
||||
sampler_info.wrap_w = gfx::WrapMode::kClampToEdge;
|
||||
sampler_info.anisotropic_filtering = false; // Copilot says not to use aniso for shadow maps
|
||||
shadow_map_sampler = device_->CreateSampler(sampler_info);
|
||||
|
||||
device_->UpdateDescriptorCombinedImageSampler(global_uniform.set, 2, shadow_map, shadow_map_sampler);
|
||||
}
|
||||
gfx::VertexFormat shadowVertexFormat{};
|
||||
shadowVertexFormat.stride = sizeof(float) * 12; // using the full meshes so a lot of data is skipped
|
||||
shadowVertexFormat.attribute_descriptions.emplace_back(0, gfx::VertexAttribFormat::kFloat3, 0); // position
|
||||
gfx::PipelineInfo shadowPipelineInfo{};
|
||||
shadowPipelineInfo.vert_shader_path = GetResourcePath("engine/shaders/shadow.vert");
|
||||
shadowPipelineInfo.frag_shader_path = GetResourcePath("engine/shaders/shadow.frag");
|
||||
shadowPipelineInfo.vertex_format = shadowVertexFormat;
|
||||
shadowPipelineInfo.face_cull_mode = gfx::CullMode::kCullBack;
|
||||
shadowPipelineInfo.alpha_blending = false;
|
||||
shadowPipelineInfo.write_z = true;
|
||||
shadowPipelineInfo.line_primitives = false;
|
||||
shadowPipelineInfo.depth_attachment_only = true;
|
||||
shadowPipelineInfo.descriptor_set_layouts.emplace_back(GetGlobalSetLayout());
|
||||
shadow_pipeline = device_->CreatePipeline(shadowPipelineInfo);
|
||||
};
|
||||
|
||||
Renderer::~Renderer()
|
||||
{
|
||||
device_->DestroyPipeline(shadow_pipeline);
|
||||
|
||||
device_->DestroySampler(shadow_map_sampler);
|
||||
device_->DestroyImage(shadow_map);
|
||||
|
||||
@ -248,16 +248,56 @@ void Renderer::PreRender(bool window_is_resized, glm::mat4 camera_transform)
|
||||
const glm::mat4 view_matrix = glm::inverse(camera_transform);
|
||||
frame_uniform.uniform_buffer_data.data = view_matrix;
|
||||
device_->WriteUniformBuffer(frame_uniform.uniform_buffer, 0, sizeof(frame_uniform.uniform_buffer_data), &frame_uniform.uniform_buffer_data);
|
||||
|
||||
// override with light matrix
|
||||
//frame_uniform.uniform_buffer_data.data = glm::mat4{1.0f};
|
||||
//device_->WriteUniformBuffer(frame_uniform.uniform_buffer, 0, sizeof(frame_uniform.uniform_buffer_data), &frame_uniform.uniform_buffer_data);
|
||||
//global_uniform.uniform_buffer_data.data.proj = global_uniform.uniform_buffer_data.data.lightSpaceMatrix;
|
||||
//device_->WriteUniformBuffer(global_uniform.uniform_buffer, 0, sizeof(global_uniform.uniform_buffer_data), &global_uniform.uniform_buffer_data);
|
||||
}
|
||||
|
||||
void Renderer::Render(const RenderList* static_list, const RenderList* dynamic_list, const std::vector<Line>& debug_lines)
|
||||
{
|
||||
|
||||
if (rendering_started == false) {
|
||||
// shadow mapping...
|
||||
|
||||
shadow_map = device_->CreateShadowmapImage();
|
||||
|
||||
// render to shadow map
|
||||
gfx::DrawBuffer* shadow_draw = device_->BeginShadowmapRender(shadow_map);
|
||||
device_->CmdBindPipeline(shadow_draw, shadow_pipeline);
|
||||
device_->CmdBindDescriptorSet(shadow_draw, shadow_pipeline, global_uniform.set, 0); // only need light space matrix
|
||||
if (static_list) {
|
||||
if (!static_list->empty()) {
|
||||
for (const auto& entry : *static_list) {
|
||||
device_->CmdPushConstants(shadow_draw, shadow_pipeline, 0, sizeof(entry.model_matrix), &entry.model_matrix);
|
||||
device_->CmdBindVertexBuffer(shadow_draw, 0, entry.vertex_buffer);
|
||||
device_->CmdBindIndexBuffer(shadow_draw, entry.index_buffer);
|
||||
device_->CmdDrawIndexed(shadow_draw, entry.index_count, 1, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dynamic_list) {
|
||||
if (!dynamic_list->empty()) {
|
||||
for (const auto& entry : *dynamic_list) {
|
||||
device_->CmdPushConstants(shadow_draw, shadow_pipeline, 0, sizeof(entry.model_matrix), &entry.model_matrix);
|
||||
device_->CmdBindVertexBuffer(shadow_draw, 0, entry.vertex_buffer);
|
||||
device_->CmdBindIndexBuffer(shadow_draw, entry.index_buffer);
|
||||
device_->CmdDrawIndexed(shadow_draw, entry.index_count, 1, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
device_->FinishShadowmapRender(shadow_draw, shadow_map);
|
||||
|
||||
gfx::SamplerInfo sampler_info{};
|
||||
sampler_info.magnify = gfx::Filter::kLinear;
|
||||
sampler_info.minify = gfx::Filter::kLinear;
|
||||
sampler_info.mipmap = gfx::Filter::kLinear; // trilinear is apparently good for shadow maps
|
||||
sampler_info.wrap_u = gfx::WrapMode::kClampToEdge;
|
||||
sampler_info.wrap_v = gfx::WrapMode::kClampToEdge;
|
||||
sampler_info.wrap_w = gfx::WrapMode::kClampToEdge;
|
||||
sampler_info.anisotropic_filtering = false; // Copilot says not to use aniso for shadow maps
|
||||
shadow_map_sampler = device_->CreateSampler(sampler_info);
|
||||
|
||||
device_->UpdateDescriptorCombinedImageSampler(global_uniform.set, 2, shadow_map, shadow_map_sampler);
|
||||
}
|
||||
rendering_started = true;
|
||||
|
||||
last_bound_pipeline_ = nullptr;
|
||||
|
||||
gfx::DrawBuffer* draw_buffer = device_->BeginRender();
|
||||
|
Loading…
Reference in New Issue
Block a user