feat: basic shadow map + renderdoc labels
This commit is contained in:
@@ -39,6 +39,9 @@ public:
|
||||
[[nodiscard]] float GetInnerConeAngle() const { return m_InnerConeAngle; }
|
||||
[[nodiscard]] float GetOuterConeAngle() const { return m_OuterConeAngle; }
|
||||
|
||||
void SetCastShadows(bool castShadows) { m_CastShadows = castShadows; }
|
||||
[[nodiscard]] bool GetCastShadows() const { return m_CastShadows; }
|
||||
|
||||
private:
|
||||
LightType m_Type{LightType::Point};
|
||||
glm::vec3 m_Color{1.0f};
|
||||
@@ -46,6 +49,7 @@ private:
|
||||
float m_Range{10.0f};
|
||||
float m_InnerConeAngle{0.35f};
|
||||
float m_OuterConeAngle{0.5f};
|
||||
bool m_CastShadows{false};
|
||||
};
|
||||
|
||||
#endif // LIGHTCOMPONENT_H
|
||||
|
||||
@@ -25,6 +25,9 @@ struct Light {
|
||||
|
||||
float innerConeAngle{0.35f};
|
||||
float outerConeAngle{0.5f};
|
||||
|
||||
// directional lights only, the first one submitted each frame gets the shadow map
|
||||
bool castShadows{false};
|
||||
};
|
||||
|
||||
struct GPULight {
|
||||
@@ -39,7 +42,8 @@ struct GPULight {
|
||||
|
||||
float spotInnerCos;
|
||||
float spotOuterCos;
|
||||
glm::vec2 padding;
|
||||
std::uint32_t castShadows;
|
||||
float padding;
|
||||
};
|
||||
|
||||
static_assert(sizeof(GPULight) == 64, "GPULight must match the struct in lights.glsl");
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#ifndef SHADOWMAPPIPELINE_H
|
||||
#define SHADOWMAPPIPELINE_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include <destrum/Graphics/Pipeline.h>
|
||||
#include <destrum/Graphics/ids.h>
|
||||
#include <destrum/Graphics/MeshDrawCommand.h>
|
||||
#include <destrum/Graphics/Resources/Buffer.h>
|
||||
|
||||
class GfxDevice;
|
||||
class RenderResources;
|
||||
|
||||
// Renders the depth of the scene as seen from a directional light, centered around the camera
|
||||
class ShadowMapPipeline final
|
||||
{
|
||||
public:
|
||||
static constexpr std::uint32_t SHADOW_MAP_SIZE = 2048;
|
||||
|
||||
void init(GfxDevice& gfxDevice, RenderResources& resources);
|
||||
void cleanup(VkDevice device);
|
||||
|
||||
void draw(
|
||||
VkCommandBuffer cmd,
|
||||
const RenderResources& resources,
|
||||
const GPUBuffer& sceneDataBuffer,
|
||||
const std::vector<MeshDrawCommand>& drawCommands,
|
||||
const std::vector<std::size_t>& sortedDrawCommands);
|
||||
|
||||
[[nodiscard]] glm::mat4 calculateLightViewProj(const glm::vec3& lightDirection, const glm::vec3& center) const;
|
||||
|
||||
[[nodiscard]] ImageID getShadowMapId() const { return shadowMapId; }
|
||||
[[nodiscard]] float getNormalOffset() const;
|
||||
|
||||
// half the width of the area around the camera that receives shadows
|
||||
void setShadowDistance(float distance) { shadowDistance = glm::max(distance, 1.0f); }
|
||||
[[nodiscard]] float getShadowDistance() const { return shadowDistance; }
|
||||
|
||||
private:
|
||||
struct PushConstants
|
||||
{
|
||||
glm::mat4 transform;
|
||||
VkDeviceAddress sceneDataBuffer;
|
||||
VkDeviceAddress vertexBuffer;
|
||||
std::uint32_t materialId;
|
||||
std::uint32_t padding;
|
||||
};
|
||||
|
||||
VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE};
|
||||
std::unique_ptr<Pipeline> m_pipeline;
|
||||
|
||||
VkFormat shadowMapFormat{VK_FORMAT_D32_SFLOAT};
|
||||
ImageID shadowMapId{NULL_IMAGE_ID};
|
||||
|
||||
float shadowDistance{25.0f};
|
||||
// how far in front of / behind the camera (along the light) casters are still captured
|
||||
float shadowDepthRange{100.0f};
|
||||
};
|
||||
|
||||
#endif //SHADOWMAPPIPELINE_H
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <destrum/Graphics/Pipelines/LineRenderingPass.h>
|
||||
#include <destrum/Graphics/Pipelines/MeshPipeline.h>
|
||||
#include <destrum/Graphics/Pipelines/QuadRendererPass.h>
|
||||
#include <destrum/Graphics/Pipelines/ShadowMapPipeline.h>
|
||||
#include <destrum/Graphics/ids.h>
|
||||
#include <destrum/Graphics/MeshDrawCommand.h>
|
||||
#include <destrum/Graphics/Resources/NBuffer.h>
|
||||
@@ -17,6 +18,7 @@
|
||||
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <destrum/Graphics/Pipelines/SkinningPipeline.h>
|
||||
|
||||
@@ -87,6 +89,16 @@ public:
|
||||
return renderLightHeatmap;
|
||||
}
|
||||
|
||||
void setShadowDistance(float distance)
|
||||
{
|
||||
shadowMapPipeline->setShadowDistance(distance);
|
||||
}
|
||||
|
||||
float getShadowDistance() const
|
||||
{
|
||||
return shadowMapPipeline->getShadowDistance();
|
||||
}
|
||||
|
||||
RenderResources* getResources()
|
||||
{
|
||||
return resources;
|
||||
@@ -138,7 +150,11 @@ private:
|
||||
std::uint32_t numLights;
|
||||
std::uint32_t tileCountX;
|
||||
std::uint32_t debugLightHeatmap;
|
||||
|
||||
std::uint32_t shadowMapId;
|
||||
float shadowNormalOffset;
|
||||
std::uint32_t padding;
|
||||
glm::mat4 lightViewProj;
|
||||
};
|
||||
|
||||
NBuffer sceneDataBuffer;
|
||||
@@ -150,6 +166,9 @@ private:
|
||||
|
||||
std::unique_ptr<SkinningPipeline> skinningPipeline;
|
||||
std::unique_ptr<LightCullingPipeline> lightCullingPipeline;
|
||||
std::unique_ptr<ShadowMapPipeline> shadowMapPipeline;
|
||||
|
||||
std::optional<glm::vec3> shadowLightDirection;
|
||||
|
||||
bool renderLightHeatmap{false};
|
||||
bool initialized{false};
|
||||
|
||||
@@ -77,6 +77,8 @@ public:
|
||||
[[nodiscard]] VkFormat getFormat() const { return m_swapchain.image_format; }
|
||||
|
||||
private:
|
||||
void nameSwapchainObjects(VkDevice device) const;
|
||||
|
||||
struct FrameData {
|
||||
VkSemaphore swapchainSemaphore{VK_NULL_HANDLE};
|
||||
VkFence renderFence{VK_NULL_HANDLE};
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
@@ -87,6 +89,9 @@ namespace vkutil {
|
||||
VkDeviceSize offset = 0,
|
||||
VkDeviceSize size = VK_WHOLE_SIZE);
|
||||
|
||||
// Object names (VK_EXT_debug_utils), shown in RenderDoc, Nsight and validation messages.
|
||||
// All of these are no-ops when the extension isn't loaded.
|
||||
void addDebugLabel(VkDevice device, VkObjectType objectType, std::uint64_t objectHandle, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkImage image, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkImageView imageView, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkShaderModule shaderModule, const char* label);
|
||||
@@ -94,6 +99,62 @@ namespace vkutil {
|
||||
void addDebugLabel(VkDevice device, VkPipelineLayout layout, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkBuffer buffer, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkSampler sampler, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkDescriptorPool descriptorPool, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkDescriptorSet descriptorSet, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkCommandPool commandPool, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkCommandBuffer commandBuffer, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkFence fence, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkSemaphore semaphore, const char* label);
|
||||
void addDebugLabel(VkDevice device, VkQueue queue, const char* label);
|
||||
|
||||
// Command buffer regions, they nest like a stack: every begin needs a matching end
|
||||
// in the same command buffer.
|
||||
[[nodiscard]] bool debugLabelsEnabled();
|
||||
void cmdBeginLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color = glm::vec4{1.0f});
|
||||
void cmdEndLabel(VkCommandBuffer cmd);
|
||||
void cmdInsertLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color = glm::vec4{1.0f});
|
||||
|
||||
// printf style, only formats when labels are actually recorded (cheap enough for per draw labels)
|
||||
template <typename... Args>
|
||||
void cmdBeginLabelFormatted(VkCommandBuffer cmd, const glm::vec4& color, const char* format, Args... args)
|
||||
{
|
||||
if (!debugLabelsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
char label[256];
|
||||
std::snprintf(label, sizeof(label), format, args...);
|
||||
cmdBeginLabel(cmd, label, color);
|
||||
}
|
||||
|
||||
class ScopedCmdLabel {
|
||||
public:
|
||||
ScopedCmdLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color = glm::vec4{1.0f});
|
||||
~ScopedCmdLabel();
|
||||
|
||||
ScopedCmdLabel(const ScopedCmdLabel& other) = delete;
|
||||
ScopedCmdLabel(ScopedCmdLabel&& other) noexcept = delete;
|
||||
ScopedCmdLabel& operator=(const ScopedCmdLabel& other) = delete;
|
||||
ScopedCmdLabel& operator=(ScopedCmdLabel&& other) noexcept = delete;
|
||||
|
||||
private:
|
||||
VkCommandBuffer cmd{VK_NULL_HANDLE};
|
||||
};
|
||||
|
||||
// Colors used for the renderer's labels, so passes are easy to tell apart in a capture
|
||||
namespace labelColors {
|
||||
inline const glm::vec4 frame{0.8f, 0.8f, 0.8f, 1.0f};
|
||||
inline const glm::vec4 compute{0.9f, 0.5f, 0.1f, 1.0f};
|
||||
inline const glm::vec4 shadow{0.3f, 0.3f, 0.6f, 1.0f};
|
||||
inline const glm::vec4 depth{0.4f, 0.4f, 0.4f, 1.0f};
|
||||
inline const glm::vec4 opaque{0.2f, 0.7f, 0.3f, 1.0f};
|
||||
inline const glm::vec4 sky{0.3f, 0.6f, 0.9f, 1.0f};
|
||||
inline const glm::vec4 debug{0.9f, 0.2f, 0.6f, 1.0f};
|
||||
inline const glm::vec4 ui{0.9f, 0.9f, 0.2f, 1.0f};
|
||||
inline const glm::vec4 transfer{0.6f, 0.4f, 0.2f, 1.0f};
|
||||
inline const glm::vec4 draw{0.5f, 0.8f, 0.5f, 1.0f};
|
||||
}
|
||||
|
||||
struct RenderingInfoParams {
|
||||
VkExtent2D renderExtent;
|
||||
|
||||
Reference in New Issue
Block a user