feat: basic shadow map + renderdoc labels
This commit is contained in:
@@ -50,6 +50,7 @@ set(SRC_FILES
|
|||||||
"src/Graphics/Pipelines/QuadRendererPass.cpp"
|
"src/Graphics/Pipelines/QuadRendererPass.cpp"
|
||||||
"src/Graphics/Pipelines/SkyboxPipeline.cpp"
|
"src/Graphics/Pipelines/SkyboxPipeline.cpp"
|
||||||
"src/Graphics/Pipelines/LightCullingPipeline.cpp"
|
"src/Graphics/Pipelines/LightCullingPipeline.cpp"
|
||||||
|
"src/Graphics/Pipelines/ShadowMapPipeline.cpp"
|
||||||
"src/Graphics/Pipelines/SkinningPipeline.cpp"
|
"src/Graphics/Pipelines/SkinningPipeline.cpp"
|
||||||
"src/Graphics/Pipelines/ImguiPass.cpp"
|
"src/Graphics/Pipelines/ImguiPass.cpp"
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ vec4 sampleTextureCubeLinear(uint texID, vec3 p) {
|
|||||||
return texture(nonuniformEXT(samplerCube(textureCubes[texID], samplers[LINEAR_SAMPLER_ID])), p);
|
return texture(nonuniformEXT(samplerCube(textureCubes[texID], samplers[LINEAR_SAMPLER_ID])), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float sampleTexture2DShadow(uint texID, vec3 p) {
|
||||||
|
return texture(nonuniformEXT(sampler2DShadow(textures[texID], samplers[SHADOW_SAMPLER_ID])), p);
|
||||||
|
}
|
||||||
|
|
||||||
float sampleTextureArrayShadow(uint texID, vec4 p) {
|
float sampleTextureArrayShadow(uint texID, vec4 p) {
|
||||||
return texture(nonuniformEXT(sampler2DArrayShadow(textureArrays[texID], samplers[SHADOW_SAMPLER_ID])), p);
|
return texture(nonuniformEXT(sampler2DArrayShadow(textureArrays[texID], samplers[SHADOW_SAMPLER_ID])), p);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ float calculateSpotAttenuation(Light light, vec3 l)
|
|||||||
}
|
}
|
||||||
|
|
||||||
vec3 calculateLight(Light light, vec3 fragPos, vec3 n, vec3 v,
|
vec3 calculateLight(Light light, vec3 fragPos, vec3 n, vec3 v,
|
||||||
vec3 diffuseColor, float roughness, float metallic, vec3 f0)
|
vec3 diffuseColor, float roughness, float metallic, vec3 f0, float occlusion)
|
||||||
{
|
{
|
||||||
vec3 l;
|
vec3 l;
|
||||||
float attenuation = 1.0;
|
float attenuation = 1.0;
|
||||||
@@ -80,7 +80,7 @@ vec3 calculateLight(Light light, vec3 fragPos, vec3 n, vec3 v,
|
|||||||
vec3 kd = (vec3(1.0) - F) * (1.0 - metallic);
|
vec3 kd = (vec3(1.0) - F) * (1.0 - metallic);
|
||||||
vec3 diffuse = kd * diffuseColor / PI;
|
vec3 diffuse = kd * diffuseColor / PI;
|
||||||
|
|
||||||
return (diffuse + specular) * light.color * light.intensity * attenuation * NoL;
|
return (diffuse + specular) * light.color * light.intensity * attenuation * NoL * occlusion;
|
||||||
}
|
}
|
||||||
|
|
||||||
// blue -> green -> red, used to visualise how many lights a tile has
|
// blue -> green -> red, used to visualise how many lights a tile has
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ struct Light {
|
|||||||
|
|
||||||
float spotInnerCos;
|
float spotInnerCos;
|
||||||
float spotOuterCos;
|
float spotOuterCos;
|
||||||
vec2 padding;
|
uint castShadows;
|
||||||
|
float padding;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout (buffer_reference, std430) readonly buffer LightsBuffer {
|
layout (buffer_reference, std430) readonly buffer LightsBuffer {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "scene_data.glsl"
|
#include "scene_data.glsl"
|
||||||
#include "mesh_pcs.glsl"
|
#include "mesh_pcs.glsl"
|
||||||
#include "lighting.glsl"
|
#include "lighting.glsl"
|
||||||
|
#include "shadows.glsl"
|
||||||
|
|
||||||
layout (location = 0) in vec3 inPos;
|
layout (location = 0) in vec3 inPos;
|
||||||
layout (location = 1) in vec2 inUV;
|
layout (location = 1) in vec2 inUV;
|
||||||
@@ -69,8 +70,17 @@ void main()
|
|||||||
uint lightIndex = pcs.sceneData.tileLightIndices.data[tileOffset + 1 + i];
|
uint lightIndex = pcs.sceneData.tileLightIndices.data[tileOffset + 1 + i];
|
||||||
Light light = pcs.sceneData.lights.data[lightIndex];
|
Light light = pcs.sceneData.lights.data[lightIndex];
|
||||||
|
|
||||||
|
float occlusion = 1.0;
|
||||||
|
if (light.castShadows != 0) {
|
||||||
|
occlusion = calculateDirectionalShadow(
|
||||||
|
fragPos, n,
|
||||||
|
pcs.sceneData.lightViewProj,
|
||||||
|
pcs.sceneData.shadowMapId,
|
||||||
|
pcs.sceneData.shadowNormalOffset);
|
||||||
|
}
|
||||||
|
|
||||||
fragColor += calculateLight(light, fragPos, n, v,
|
fragColor += calculateLight(light, fragPos, n, v,
|
||||||
diffuseColor, roughness, metallic, f0);
|
diffuseColor, roughness, metallic, f0, occlusion);
|
||||||
}
|
}
|
||||||
|
|
||||||
// emissive
|
// emissive
|
||||||
|
|||||||
@@ -33,7 +33,12 @@ layout (buffer_reference, scalar) readonly buffer SceneDataBuffer {
|
|||||||
uint numLights;
|
uint numLights;
|
||||||
uint tileCountX;
|
uint tileCountX;
|
||||||
uint debugLightHeatmap;
|
uint debugLightHeatmap;
|
||||||
|
|
||||||
|
// directional shadows
|
||||||
|
uint shadowMapId;
|
||||||
|
float shadowNormalOffset;
|
||||||
uint padding;
|
uint padding;
|
||||||
|
mat4 lightViewProj;
|
||||||
} sceneDataBuffer;
|
} sceneDataBuffer;
|
||||||
|
|
||||||
#endif // SCENE_DATA_GLSL
|
#endif // SCENE_DATA_GLSL
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : require
|
||||||
|
|
||||||
|
#include "mesh_pcs.glsl"
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
Vertex v = pcs.vertexBuffer.vertices[gl_VertexIndex];
|
||||||
|
|
||||||
|
gl_Position = pcs.sceneData.lightViewProj * pcs.transform * vec4(v.position, 1.0f);
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef SHADOWS_GLSL
|
||||||
|
#define SHADOWS_GLSL
|
||||||
|
|
||||||
|
// expects bindless.glsl to be included before this file (it has no include guard)
|
||||||
|
|
||||||
|
// Returns 1.0 when fully lit, 0.0 when fully in shadow
|
||||||
|
float calculateDirectionalShadow(vec3 fragPos, vec3 n, mat4 lightViewProj, uint shadowMapID, float normalOffset)
|
||||||
|
{
|
||||||
|
// pushing the sample point along the normal hides most of the shadow acne
|
||||||
|
vec4 lightClip = lightViewProj * vec4(fragPos + n * normalOffset, 1.0);
|
||||||
|
vec3 lightNDC = lightClip.xyz / lightClip.w;
|
||||||
|
vec2 uv = lightNDC.xy * 0.5 + 0.5;
|
||||||
|
|
||||||
|
// outside the shadow map counts as lit
|
||||||
|
if (any(lessThan(uv, vec2(0.0))) || any(greaterThan(uv, vec2(1.0))) || lightNDC.z > 1.0) {
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 texelSize = 1.0 / vec2(textureSize(sampler2DShadow(textures[shadowMapID], samplers[SHADOW_SAMPLER_ID]), 0));
|
||||||
|
|
||||||
|
// 3x3 PCF, every tap is already bilinearly filtered by the compare sampler
|
||||||
|
float shadowed = 0.0;
|
||||||
|
for (int x = -1; x <= 1; x++) {
|
||||||
|
for (int y = -1; y <= 1; y++) {
|
||||||
|
shadowed += sampleTexture2DShadow(shadowMapID, vec3(uv + vec2(x, y) * texelSize, lightNDC.z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the shadow sampler compares with GREATER_OR_EQUAL (it was set up for reversed Z),
|
||||||
|
// with regular depth that returns 1 when the fragment is behind the occluder
|
||||||
|
return 1.0 - shadowed / 9.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SHADOWS_GLSL
|
||||||
@@ -39,6 +39,9 @@ public:
|
|||||||
[[nodiscard]] float GetInnerConeAngle() const { return m_InnerConeAngle; }
|
[[nodiscard]] float GetInnerConeAngle() const { return m_InnerConeAngle; }
|
||||||
[[nodiscard]] float GetOuterConeAngle() const { return m_OuterConeAngle; }
|
[[nodiscard]] float GetOuterConeAngle() const { return m_OuterConeAngle; }
|
||||||
|
|
||||||
|
void SetCastShadows(bool castShadows) { m_CastShadows = castShadows; }
|
||||||
|
[[nodiscard]] bool GetCastShadows() const { return m_CastShadows; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LightType m_Type{LightType::Point};
|
LightType m_Type{LightType::Point};
|
||||||
glm::vec3 m_Color{1.0f};
|
glm::vec3 m_Color{1.0f};
|
||||||
@@ -46,6 +49,7 @@ private:
|
|||||||
float m_Range{10.0f};
|
float m_Range{10.0f};
|
||||||
float m_InnerConeAngle{0.35f};
|
float m_InnerConeAngle{0.35f};
|
||||||
float m_OuterConeAngle{0.5f};
|
float m_OuterConeAngle{0.5f};
|
||||||
|
bool m_CastShadows{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LIGHTCOMPONENT_H
|
#endif // LIGHTCOMPONENT_H
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ struct Light {
|
|||||||
|
|
||||||
float innerConeAngle{0.35f};
|
float innerConeAngle{0.35f};
|
||||||
float outerConeAngle{0.5f};
|
float outerConeAngle{0.5f};
|
||||||
|
|
||||||
|
// directional lights only, the first one submitted each frame gets the shadow map
|
||||||
|
bool castShadows{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GPULight {
|
struct GPULight {
|
||||||
@@ -39,7 +42,8 @@ struct GPULight {
|
|||||||
|
|
||||||
float spotInnerCos;
|
float spotInnerCos;
|
||||||
float spotOuterCos;
|
float spotOuterCos;
|
||||||
glm::vec2 padding;
|
std::uint32_t castShadows;
|
||||||
|
float padding;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(GPULight) == 64, "GPULight must match the struct in lights.glsl");
|
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/LineRenderingPass.h>
|
||||||
#include <destrum/Graphics/Pipelines/MeshPipeline.h>
|
#include <destrum/Graphics/Pipelines/MeshPipeline.h>
|
||||||
#include <destrum/Graphics/Pipelines/QuadRendererPass.h>
|
#include <destrum/Graphics/Pipelines/QuadRendererPass.h>
|
||||||
|
#include <destrum/Graphics/Pipelines/ShadowMapPipeline.h>
|
||||||
#include <destrum/Graphics/ids.h>
|
#include <destrum/Graphics/ids.h>
|
||||||
#include <destrum/Graphics/MeshDrawCommand.h>
|
#include <destrum/Graphics/MeshDrawCommand.h>
|
||||||
#include <destrum/Graphics/Resources/NBuffer.h>
|
#include <destrum/Graphics/Resources/NBuffer.h>
|
||||||
@@ -17,6 +18,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include <destrum/Graphics/Pipelines/SkinningPipeline.h>
|
#include <destrum/Graphics/Pipelines/SkinningPipeline.h>
|
||||||
|
|
||||||
@@ -87,6 +89,16 @@ public:
|
|||||||
return renderLightHeatmap;
|
return renderLightHeatmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setShadowDistance(float distance)
|
||||||
|
{
|
||||||
|
shadowMapPipeline->setShadowDistance(distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getShadowDistance() const
|
||||||
|
{
|
||||||
|
return shadowMapPipeline->getShadowDistance();
|
||||||
|
}
|
||||||
|
|
||||||
RenderResources* getResources()
|
RenderResources* getResources()
|
||||||
{
|
{
|
||||||
return resources;
|
return resources;
|
||||||
@@ -138,7 +150,11 @@ private:
|
|||||||
std::uint32_t numLights;
|
std::uint32_t numLights;
|
||||||
std::uint32_t tileCountX;
|
std::uint32_t tileCountX;
|
||||||
std::uint32_t debugLightHeatmap;
|
std::uint32_t debugLightHeatmap;
|
||||||
|
|
||||||
|
std::uint32_t shadowMapId;
|
||||||
|
float shadowNormalOffset;
|
||||||
std::uint32_t padding;
|
std::uint32_t padding;
|
||||||
|
glm::mat4 lightViewProj;
|
||||||
};
|
};
|
||||||
|
|
||||||
NBuffer sceneDataBuffer;
|
NBuffer sceneDataBuffer;
|
||||||
@@ -150,6 +166,9 @@ private:
|
|||||||
|
|
||||||
std::unique_ptr<SkinningPipeline> skinningPipeline;
|
std::unique_ptr<SkinningPipeline> skinningPipeline;
|
||||||
std::unique_ptr<LightCullingPipeline> lightCullingPipeline;
|
std::unique_ptr<LightCullingPipeline> lightCullingPipeline;
|
||||||
|
std::unique_ptr<ShadowMapPipeline> shadowMapPipeline;
|
||||||
|
|
||||||
|
std::optional<glm::vec3> shadowLightDirection;
|
||||||
|
|
||||||
bool renderLightHeatmap{false};
|
bool renderLightHeatmap{false};
|
||||||
bool initialized{false};
|
bool initialized{false};
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ public:
|
|||||||
[[nodiscard]] VkFormat getFormat() const { return m_swapchain.image_format; }
|
[[nodiscard]] VkFormat getFormat() const { return m_swapchain.image_format; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void nameSwapchainObjects(VkDevice device) const;
|
||||||
|
|
||||||
struct FrameData {
|
struct FrameData {
|
||||||
VkSemaphore swapchainSemaphore{VK_NULL_HANDLE};
|
VkSemaphore swapchainSemaphore{VK_NULL_HANDLE};
|
||||||
VkFence renderFence{VK_NULL_HANDLE};
|
VkFence renderFence{VK_NULL_HANDLE};
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef UTIL_H
|
#ifndef UTIL_H
|
||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -87,6 +89,9 @@ namespace vkutil {
|
|||||||
VkDeviceSize offset = 0,
|
VkDeviceSize offset = 0,
|
||||||
VkDeviceSize size = VK_WHOLE_SIZE);
|
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, VkImage image, const char* label);
|
||||||
void addDebugLabel(VkDevice device, VkImageView imageView, const char* label);
|
void addDebugLabel(VkDevice device, VkImageView imageView, const char* label);
|
||||||
void addDebugLabel(VkDevice device, VkShaderModule shaderModule, 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, VkPipelineLayout layout, const char* label);
|
||||||
void addDebugLabel(VkDevice device, VkBuffer buffer, 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, 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 {
|
struct RenderingInfoParams {
|
||||||
VkExtent2D renderExtent;
|
VkExtent2D renderExtent;
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ void LightComponent::Render(const RenderContext& ctx)
|
|||||||
.range = m_Range,
|
.range = m_Range,
|
||||||
.innerConeAngle = m_InnerConeAngle,
|
.innerConeAngle = m_InnerConeAngle,
|
||||||
.outerConeAngle = m_OuterConeAngle,
|
.outerConeAngle = m_OuterConeAngle,
|
||||||
|
.castShadows = m_CastShadows,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +58,8 @@ nlohmann::json LightComponent::Serialize() const {
|
|||||||
{"intensity", m_Intensity},
|
{"intensity", m_Intensity},
|
||||||
{"range", m_Range},
|
{"range", m_Range},
|
||||||
{"innerConeAngle", m_InnerConeAngle},
|
{"innerConeAngle", m_InnerConeAngle},
|
||||||
{"outerConeAngle", m_OuterConeAngle}
|
{"outerConeAngle", m_OuterConeAngle},
|
||||||
|
{"castShadows", m_CastShadows}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +90,10 @@ void LightComponent::Deserialize(const nlohmann::json& data) {
|
|||||||
outerConeAngle = data.at("outerConeAngle").get<float>();
|
outerConeAngle = data.at("outerConeAngle").get<float>();
|
||||||
}
|
}
|
||||||
SetConeAngles(innerConeAngle, outerConeAngle);
|
SetConeAngles(innerConeAngle, outerConeAngle);
|
||||||
|
|
||||||
|
if (data.contains("castShadows")) {
|
||||||
|
m_CastShadows = data.at("castShadows").get<bool>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightComponent::ImGuiInspector() {
|
void LightComponent::ImGuiInspector() {
|
||||||
@@ -106,6 +112,9 @@ void LightComponent::ImGuiInspector() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_Type == LightType::Directional) {
|
if (m_Type == LightType::Directional) {
|
||||||
|
ImGui::Checkbox("Cast Shadows", &m_CastShadows);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextDisabled("(first directional light only)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ void MeshRendererComponent::Start() {
|
|||||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
||||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const std::string bufferName = GetGameObject()->GetName() + " (skinned vertices)";
|
||||||
|
vkutil::addDebugLabel(gfxDevice.getDevice(), m_skinnedMesh->skinnedVertexBuffer.buffer, bufferName.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ void BindlessSetManager::init(
|
|||||||
};
|
};
|
||||||
|
|
||||||
VK_CHECK(vkCreateDescriptorPool(device, &poolInfo, nullptr, &descPool));
|
VK_CHECK(vkCreateDescriptorPool(device, &poolInfo, nullptr, &descPool));
|
||||||
|
vkutil::addDebugLabel(device, descPool, "bindless descriptor pool");
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // build desc set layout
|
{ // build desc set layout
|
||||||
@@ -111,6 +112,7 @@ void BindlessSetManager::init(
|
|||||||
};
|
};
|
||||||
|
|
||||||
VK_CHECK(vkCreateDescriptorSetLayout(device, &info, nullptr, &descSetLayout));
|
VK_CHECK(vkCreateDescriptorSetLayout(device, &info, nullptr, &descSetLayout));
|
||||||
|
vkutil::addDebugLabel(device, descSetLayout, "bindless descriptor set layout");
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // alloc desc set
|
{ // alloc desc set
|
||||||
@@ -122,6 +124,7 @@ void BindlessSetManager::init(
|
|||||||
};
|
};
|
||||||
|
|
||||||
VK_CHECK(vkAllocateDescriptorSets(device, &allocInfo, &descSet));
|
VK_CHECK(vkAllocateDescriptorSets(device, &allocInfo, &descSet));
|
||||||
|
vkutil::addDebugLabel(device, descSet, "bindless descriptor set");
|
||||||
}
|
}
|
||||||
|
|
||||||
initDefaultSamplers(device, maxAnisotropy);
|
initDefaultSamplers(device, maxAnisotropy);
|
||||||
|
|||||||
@@ -99,8 +99,13 @@ void ComputePipeline::CreateComputePipeline(const std::string& compPath,
|
|||||||
throw std::runtime_error("Can't make compute pipeline!");
|
throw std::runtime_error("Can't make compute pipeline!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vkutil::addDebugLabel(m_device.getDevice(), m_compShaderModule, compFileName.c_str());
|
||||||
|
|
||||||
if (!configInfo.name.empty()) {
|
if (!configInfo.name.empty()) {
|
||||||
vkutil::addDebugLabel(GameState::GetInstance().Gfx().getDevice(), m_computePipeline, configInfo.name.c_str());
|
vkutil::addDebugLabel(m_device.getDevice(), m_computePipeline, configInfo.name.c_str());
|
||||||
|
|
||||||
|
const std::string layoutName = configInfo.name + " Layout";
|
||||||
|
vkutil::addDebugLabel(m_device.getDevice(), configInfo.pipelineLayout, layoutName.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -156,6 +156,7 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
|
|||||||
|
|
||||||
auto swapchainLayout = VK_IMAGE_LAYOUT_UNDEFINED; {
|
auto swapchainLayout = VK_IMAGE_LAYOUT_UNDEFINED; {
|
||||||
ZoneScopedN("Clear Swapchain Image");
|
ZoneScopedN("Clear Swapchain Image");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "Clear Swapchain Image", vkutil::labelColors::transfer);
|
||||||
|
|
||||||
const VkImageSubresourceRange clearRange = vkinit::imageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
|
const VkImageSubresourceRange clearRange = vkinit::imageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_GENERAL);
|
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
@@ -167,6 +168,7 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
|
|||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
ZoneScopedN("Copy DrawImage To Swapchain");
|
ZoneScopedN("Copy DrawImage To Swapchain");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "Copy DrawImage To Swapchain", vkutil::labelColors::transfer);
|
||||||
|
|
||||||
vkutil::transitionImage(
|
vkutil::transitionImage(
|
||||||
cmd,
|
cmd,
|
||||||
@@ -190,6 +192,7 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
|
|||||||
|
|
||||||
if (props.imguiPass) {
|
if (props.imguiPass) {
|
||||||
ZoneScopedN("ImGui Render");
|
ZoneScopedN("ImGui Render");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "ImGui Render", vkutil::labelColors::ui);
|
||||||
|
|
||||||
props.imguiPass->render(
|
props.imguiPass->render(
|
||||||
cmd,
|
cmd,
|
||||||
@@ -202,6 +205,7 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
|
|||||||
|
|
||||||
{
|
{
|
||||||
ZoneScopedN("Transition Swapchain To Present");
|
ZoneScopedN("Transition Swapchain To Present");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "Transition Swapchain To Present", vkutil::labelColors::transfer);
|
||||||
|
|
||||||
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||||
swapchainLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
swapchainLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ void VulkanImmediateExecutor::init(
|
|||||||
};
|
};
|
||||||
VK_CHECK(vkCreateFence(deviceHandle, &fenceCreateInfo, nullptr, &immFence));
|
VK_CHECK(vkCreateFence(deviceHandle, &fenceCreateInfo, nullptr, &immFence));
|
||||||
|
|
||||||
|
vkutil::addDebugLabel(deviceHandle, immCommandPool, "immediate command pool");
|
||||||
|
vkutil::addDebugLabel(deviceHandle, immCommandBuffer, "immediate command buffer");
|
||||||
|
vkutil::addDebugLabel(deviceHandle, immFence, "immediate fence");
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
cleanup(deviceHandle);
|
cleanup(deviceHandle);
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ void FrameManager::init(VkDevice dev, std::uint32_t queueFamily) {
|
|||||||
const auto cmdAllocInfo = vkinit::commandBufferAllocateInfo(commandPool, 1);
|
const auto cmdAllocInfo = vkinit::commandBufferAllocateInfo(commandPool, 1);
|
||||||
auto& mainCommandBuffer = frames[i].commandBuffer;
|
auto& mainCommandBuffer = frames[i].commandBuffer;
|
||||||
VK_CHECK(vkAllocateCommandBuffers(device, &cmdAllocInfo, &mainCommandBuffer));
|
VK_CHECK(vkAllocateCommandBuffers(device, &cmdAllocInfo, &mainCommandBuffer));
|
||||||
|
|
||||||
|
const std::string poolName = "frame " + std::to_string(i) + " command pool";
|
||||||
|
const std::string cmdName = "frame " + std::to_string(i) + " command buffer";
|
||||||
|
vkutil::addDebugLabel(device, commandPool, poolName.c_str());
|
||||||
|
vkutil::addDebugLabel(device, mainCommandBuffer, cmdName.c_str());
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
cleanup(dev);
|
cleanup(dev);
|
||||||
|
|||||||
@@ -178,7 +178,9 @@ std::optional<GPUImage> ImageManager::loadImageFromFile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
image.debugName = path.string();
|
image.debugName = path.string();
|
||||||
vkutil::addDebugLabel(device, image.image, path.string().c_str());
|
vkutil::addDebugLabel(device, image.image, image.debugName.c_str());
|
||||||
|
const std::string viewName = image.debugName + " (view)";
|
||||||
|
vkutil::addDebugLabel(device, image.imageView, viewName.c_str());
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,6 +156,9 @@ void MeshCache::uploadMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh, GPUMesh
|
|||||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
||||||
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE);
|
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE);
|
||||||
|
|
||||||
|
const auto skinningBufferName = cpuMesh.name + " (skinning data)";
|
||||||
|
vkutil::addDebugLabel(gfxDevice.getDevice(), gpuMesh.skinningDataBuffer.buffer, skinningBufferName.c_str());
|
||||||
|
|
||||||
auto skinningStaging =
|
auto skinningStaging =
|
||||||
gfxDevice.createBuffer(
|
gfxDevice.createBuffer(
|
||||||
skinningDataSize,
|
skinningDataSize,
|
||||||
|
|||||||
@@ -146,11 +146,11 @@ void Pipeline::CreateGraphicsPipeline(const std::string& vertPath, const std::st
|
|||||||
|
|
||||||
CreateShaderModule(vertCode, &m_vertShaderModule);
|
CreateShaderModule(vertCode, &m_vertShaderModule);
|
||||||
|
|
||||||
// vkutil::addDebugLabel(
|
vkutil::addDebugLabel(
|
||||||
// m_device.getDevice(),
|
m_device.getDevice(),
|
||||||
// m_fragShaderModule,
|
m_vertShaderModule,
|
||||||
// VertFileName.c_str()
|
VertFileName.c_str()
|
||||||
// );
|
);
|
||||||
|
|
||||||
VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
|
VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
|
||||||
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
@@ -173,11 +173,11 @@ void Pipeline::CreateGraphicsPipeline(const std::string& vertPath, const std::st
|
|||||||
|
|
||||||
CreateShaderModule(fragCode, &m_fragShaderModule);
|
CreateShaderModule(fragCode, &m_fragShaderModule);
|
||||||
|
|
||||||
// vkutil::addDebugLabel(
|
vkutil::addDebugLabel(
|
||||||
// m_device.getDevice(),
|
m_device.getDevice(),
|
||||||
// m_fragShaderModule,
|
m_fragShaderModule,
|
||||||
// FragFileName.c_str()
|
FragFileName.c_str()
|
||||||
// );
|
);
|
||||||
|
|
||||||
|
|
||||||
VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
|
VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
|
||||||
@@ -231,18 +231,17 @@ void Pipeline::CreateGraphicsPipeline(const std::string& vertPath, const std::st
|
|||||||
pipelineInfo.basePipelineIndex = -1;
|
pipelineInfo.basePipelineIndex = -1;
|
||||||
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||||
|
|
||||||
if (!configInfo.name.empty()) {
|
|
||||||
// DebugLabel::SetObjectName(
|
|
||||||
// reinterpret_cast<uint64_t>(pipelineInfo.layout),
|
|
||||||
// VK_OBJECT_TYPE_PIPELINE_LAYOUT,
|
|
||||||
// configInfo.name.c_str()
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (vkCreateGraphicsPipelines(m_device.getDevice(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &m_graphicsPipeline) != VK_SUCCESS) {
|
if (vkCreateGraphicsPipelines(m_device.getDevice(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &m_graphicsPipeline) != VK_SUCCESS) {
|
||||||
throw std::runtime_error("Can't make pipeline!");
|
throw std::runtime_error("Can't make pipeline!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!configInfo.name.empty()) {
|
||||||
|
vkutil::addDebugLabel(m_device.getDevice(), m_graphicsPipeline, configInfo.name.c_str());
|
||||||
|
|
||||||
|
const std::string layoutName = configInfo.name + " Layout";
|
||||||
|
vkutil::addDebugLabel(m_device.getDevice(), configInfo.pipelineLayout, layoutName.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pipeline::CreateShaderModule(const std::vector<char>& code, VkShaderModule* shaderModule) const {
|
void Pipeline::CreateShaderModule(const std::vector<char>& code, VkShaderModule* shaderModule) const {
|
||||||
|
|||||||
@@ -158,7 +158,8 @@ void LightCullingPipeline::appendLight(const Light& light)
|
|||||||
.type = static_cast<std::uint32_t>(light.type),
|
.type = static_cast<std::uint32_t>(light.type),
|
||||||
.spotInnerCos = std::cos(light.innerConeAngle),
|
.spotInnerCos = std::cos(light.innerConeAngle),
|
||||||
.spotOuterCos = std::cos(light.outerConeAngle),
|
.spotOuterCos = std::cos(light.outerConeAngle),
|
||||||
.padding = glm::vec2{0.0f},
|
.castShadows = light.castShadows ? 1u : 0u,
|
||||||
|
.padding = 0.0f,
|
||||||
};
|
};
|
||||||
lightsBuffer.append(gpuLight);
|
lightsBuffer.append(gpuLight);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <destrum/Graphics/RenderResources.h>
|
#include <destrum/Graphics/RenderResources.h>
|
||||||
#include <destrum/Graphics/Caches/MeshCache.h>
|
#include <destrum/Graphics/Caches/MeshCache.h>
|
||||||
#include <destrum/Graphics/Frustum.h>
|
#include <destrum/Graphics/Frustum.h>
|
||||||
|
#include <destrum/Graphics/Util.h>
|
||||||
|
|
||||||
#include "volk.h"
|
#include "volk.h"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
@@ -219,6 +220,16 @@ void MeshPipeline::drawMeshes(
|
|||||||
|
|
||||||
const auto& mesh = meshCache.getMesh(dc.meshId);
|
const auto& mesh = meshCache.getMesh(dc.meshId);
|
||||||
|
|
||||||
|
const std::string& meshKey = meshCache.getMeshKey(dc.meshId);
|
||||||
|
vkutil::cmdBeginLabelFormatted(
|
||||||
|
cmd,
|
||||||
|
vkutil::labelColors::draw,
|
||||||
|
"%s [mesh %zu, material %u%s]",
|
||||||
|
meshKey.empty() ? "Mesh" : meshKey.c_str(),
|
||||||
|
dc.meshId,
|
||||||
|
dc.materialId,
|
||||||
|
dc.skinnedMesh != nullptr ? ", skinned" : "");
|
||||||
|
|
||||||
if (dc.meshId != prevMeshId)
|
if (dc.meshId != prevMeshId)
|
||||||
{
|
{
|
||||||
prevMeshId = dc.meshId;
|
prevMeshId = dc.meshId;
|
||||||
@@ -254,6 +265,8 @@ void MeshPipeline::drawMeshes(
|
|||||||
);
|
);
|
||||||
|
|
||||||
vkCmdDrawIndexed(cmd, mesh.numIndices, 1, 0, 0, 0);
|
vkCmdDrawIndexed(cmd, mesh.numIndices, 1, 0, 0, 0);
|
||||||
|
|
||||||
|
vkutil::cmdEndLabel(cmd);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!sortedDrawCommands.empty())
|
if (!sortedDrawCommands.empty())
|
||||||
|
|||||||
@@ -42,12 +42,14 @@ void QuadRendererPass::init(GfxDevice& gfxDevice, RenderResources& resources, Vk
|
|||||||
vertexBytes,
|
vertexBytes,
|
||||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||||
VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
|
VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
|
||||||
|
vkutil::addDebugLabel(gfxDevice.getDevice(), vertexBuffer.buffer, "quad vertices");
|
||||||
|
|
||||||
const std::size_t indexBytes = InitialQuadCapacity * IndicesPerQuad * sizeof(std::uint32_t);
|
const std::size_t indexBytes = InitialQuadCapacity * IndicesPerQuad * sizeof(std::uint32_t);
|
||||||
indexBuffer = gfxDevice.createBuffer(
|
indexBuffer = gfxDevice.createBuffer(
|
||||||
indexBytes,
|
indexBytes,
|
||||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||||
VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
|
VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
|
||||||
|
vkutil::addDebugLabel(gfxDevice.getDevice(), indexBuffer.buffer, "quad indices");
|
||||||
|
|
||||||
quadCapacity = InitialQuadCapacity;
|
quadCapacity = InitialQuadCapacity;
|
||||||
|
|
||||||
@@ -321,6 +323,7 @@ void QuadRendererPass::ensureCapacity(
|
|||||||
newCapacity * VerticesPerQuad * sizeof(QuadVertex),
|
newCapacity * VerticesPerQuad * sizeof(QuadVertex),
|
||||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||||
VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
|
VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
|
||||||
|
vkutil::addDebugLabel(gfxDevice.getDevice(), vertexBuffer.buffer, "quad vertices");
|
||||||
|
|
||||||
if (indexBuffer.buffer != VK_NULL_HANDLE) {
|
if (indexBuffer.buffer != VK_NULL_HANDLE) {
|
||||||
gfxDevice.destroyBuffer(indexBuffer);
|
gfxDevice.destroyBuffer(indexBuffer);
|
||||||
@@ -329,6 +332,7 @@ void QuadRendererPass::ensureCapacity(
|
|||||||
newCapacity * IndicesPerQuad * sizeof(std::uint32_t),
|
newCapacity * IndicesPerQuad * sizeof(std::uint32_t),
|
||||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||||
VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
|
VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
|
||||||
|
vkutil::addDebugLabel(gfxDevice.getDevice(), indexBuffer.buffer, "quad indices");
|
||||||
|
|
||||||
quadCapacity = newCapacity;
|
quadCapacity = newCapacity;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
#include <destrum/Graphics/Pipelines/ShadowMapPipeline.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
|
#include <destrum/FS/AssetFS.h>
|
||||||
|
#include <destrum/Graphics/GfxDevice.h>
|
||||||
|
#include <destrum/Graphics/RenderResources.h>
|
||||||
|
#include <destrum/Graphics/Caches/MeshCache.h>
|
||||||
|
#include <destrum/Graphics/Util.h>
|
||||||
|
|
||||||
|
#include "volk.h"
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
|
void ShadowMapPipeline::init(GfxDevice& gfxDevice, RenderResources& resources)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto vertexShader =
|
||||||
|
AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/shadow.vert");
|
||||||
|
|
||||||
|
const auto bufferRange = VkPushConstantRange{
|
||||||
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
.offset = 0,
|
||||||
|
.size = sizeof(PushConstants),
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto pushConstantRanges = std::array{bufferRange};
|
||||||
|
|
||||||
|
const auto layouts = std::array{
|
||||||
|
resources.getBindlessDescSetLayout()
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
||||||
|
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
pipelineLayoutInfo.setLayoutCount = static_cast<std::uint32_t>(layouts.size());
|
||||||
|
pipelineLayoutInfo.pSetLayouts = layouts.data();
|
||||||
|
pipelineLayoutInfo.pushConstantRangeCount = static_cast<std::uint32_t>(pushConstantRanges.size());
|
||||||
|
pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data();
|
||||||
|
|
||||||
|
if (vkCreatePipelineLayout(
|
||||||
|
gfxDevice.getDevice(),
|
||||||
|
&pipelineLayoutInfo,
|
||||||
|
nullptr,
|
||||||
|
&m_pipelineLayout) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Could not create shadow map pipeline layout");
|
||||||
|
}
|
||||||
|
|
||||||
|
PipelineConfigInfo pipelineConfig{};
|
||||||
|
Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
|
||||||
|
|
||||||
|
pipelineConfig.name = "Shadow Map Pipeline";
|
||||||
|
pipelineConfig.pipelineLayout = m_pipelineLayout;
|
||||||
|
|
||||||
|
pipelineConfig.vertexAttributeDescriptions = {};
|
||||||
|
pipelineConfig.vertexBindingDescriptions = {};
|
||||||
|
|
||||||
|
pipelineConfig.colorAttachments = {};
|
||||||
|
pipelineConfig.colorBlendInfo.attachmentCount = 0;
|
||||||
|
pipelineConfig.depthAttachment = shadowMapFormat;
|
||||||
|
|
||||||
|
// the light projection isn't Y flipped like the camera's, so the winding is mirrored
|
||||||
|
pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE;
|
||||||
|
pipelineConfig.rasterizationInfo.depthBiasEnable = VK_TRUE;
|
||||||
|
pipelineConfig.rasterizationInfo.depthBiasConstantFactor = 0.0f;
|
||||||
|
pipelineConfig.rasterizationInfo.depthBiasSlopeFactor = 2.0f;
|
||||||
|
|
||||||
|
m_pipeline = std::make_unique<Pipeline>(
|
||||||
|
gfxDevice,
|
||||||
|
vertexShader.string(),
|
||||||
|
"",
|
||||||
|
pipelineConfig
|
||||||
|
);
|
||||||
|
|
||||||
|
const auto createInfo = vkutil::CreateImageInfo{
|
||||||
|
.format = shadowMapFormat,
|
||||||
|
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||||
|
.extent = VkExtent3D{SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
shadowMapId = resources.createImage(gfxDevice, createInfo, "shadow map", nullptr, shadowMapId);
|
||||||
|
spdlog::info("Created {0}x{0} shadow map with id {1}", SHADOW_MAP_SIZE, shadowMapId);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
cleanup(gfxDevice.getDevice());
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowMapPipeline::cleanup(VkDevice device)
|
||||||
|
{
|
||||||
|
m_pipeline.reset();
|
||||||
|
|
||||||
|
if (m_pipelineLayout != VK_NULL_HANDLE && device != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vkDestroyPipelineLayout(device, m_pipelineLayout, nullptr);
|
||||||
|
}
|
||||||
|
m_pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
shadowMapId = NULL_IMAGE_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 ShadowMapPipeline::calculateLightViewProj(const glm::vec3& lightDirection, const glm::vec3& center) const
|
||||||
|
{
|
||||||
|
const glm::vec3 direction = glm::normalize(lightDirection);
|
||||||
|
const glm::vec3 up = std::abs(direction.y) > 0.99f ? glm::vec3{0.0f, 0.0f, 1.0f} : glm::vec3{0.0f, 1.0f, 0.0f};
|
||||||
|
|
||||||
|
const glm::mat4 lightView = glm::lookAt(glm::vec3{0.0f}, direction, up);
|
||||||
|
|
||||||
|
const float texelSize = (2.0f * shadowDistance) / static_cast<float>(SHADOW_MAP_SIZE);
|
||||||
|
glm::vec3 lightSpaceCenter = glm::vec3(lightView * glm::vec4(center, 1.0f));
|
||||||
|
lightSpaceCenter.x = std::floor(lightSpaceCenter.x / texelSize) * texelSize;
|
||||||
|
lightSpaceCenter.y = std::floor(lightSpaceCenter.y / texelSize) * texelSize;
|
||||||
|
|
||||||
|
const glm::mat4 lightProj = glm::orthoRH_ZO(
|
||||||
|
lightSpaceCenter.x - shadowDistance,
|
||||||
|
lightSpaceCenter.x + shadowDistance,
|
||||||
|
lightSpaceCenter.y - shadowDistance,
|
||||||
|
lightSpaceCenter.y + shadowDistance,
|
||||||
|
-lightSpaceCenter.z - shadowDepthRange,
|
||||||
|
-lightSpaceCenter.z + shadowDepthRange);
|
||||||
|
|
||||||
|
return lightProj * lightView;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ShadowMapPipeline::getNormalOffset() const
|
||||||
|
{
|
||||||
|
const float texelSize = (2.0f * shadowDistance) / static_cast<float>(SHADOW_MAP_SIZE);
|
||||||
|
return texelSize * 1.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowMapPipeline::draw(
|
||||||
|
VkCommandBuffer cmd,
|
||||||
|
const RenderResources& resources,
|
||||||
|
const GPUBuffer& sceneDataBuffer,
|
||||||
|
const std::vector<MeshDrawCommand>& drawCommands,
|
||||||
|
const std::vector<std::size_t>& sortedDrawCommands)
|
||||||
|
{
|
||||||
|
if (!m_pipeline || shadowMapId == NULL_IMAGE_ID)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& shadowMap = resources.getImage(shadowMapId);
|
||||||
|
|
||||||
|
vkutil::transitionImage(
|
||||||
|
cmd,
|
||||||
|
shadowMap.image,
|
||||||
|
shadowMap.layout,
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
|
||||||
|
shadowMap.setLayout(VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
|
||||||
|
|
||||||
|
auto renderInfo = vkutil::createRenderingInfo({
|
||||||
|
.renderExtent = shadowMap.getExtent2D(),
|
||||||
|
.depthImageView = shadowMap.imageView,
|
||||||
|
.depthImageClearValue = 1.f,
|
||||||
|
});
|
||||||
|
renderInfo.renderingInfo.pDepthAttachment = &renderInfo.depthAttachment;
|
||||||
|
|
||||||
|
vkCmdBeginRendering(cmd, &renderInfo.renderingInfo);
|
||||||
|
|
||||||
|
m_pipeline->bind(cmd);
|
||||||
|
resources.bindBindlessDescSet(cmd, m_pipelineLayout);
|
||||||
|
|
||||||
|
const auto viewport = VkViewport{
|
||||||
|
.x = 0.f,
|
||||||
|
.y = 0.f,
|
||||||
|
.width = static_cast<float>(SHADOW_MAP_SIZE),
|
||||||
|
.height = static_cast<float>(SHADOW_MAP_SIZE),
|
||||||
|
.minDepth = 0.f,
|
||||||
|
.maxDepth = 1.f,
|
||||||
|
};
|
||||||
|
vkCmdSetViewport(cmd, 0, 1, &viewport);
|
||||||
|
|
||||||
|
const auto scissor = VkRect2D{
|
||||||
|
.offset = {},
|
||||||
|
.extent = shadowMap.getExtent2D(),
|
||||||
|
};
|
||||||
|
vkCmdSetScissor(cmd, 0, 1, &scissor);
|
||||||
|
|
||||||
|
vkCmdSetPolygonModeEXT(cmd, VK_POLYGON_MODE_FILL);
|
||||||
|
|
||||||
|
const MeshCache& meshCache = resources.meshes();
|
||||||
|
MeshID prevMeshId = NULL_MESH_ID;
|
||||||
|
|
||||||
|
const auto drawOne = [&](const MeshDrawCommand& dc)
|
||||||
|
{
|
||||||
|
if (!dc.castShadow)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& mesh = meshCache.getMesh(dc.meshId);
|
||||||
|
|
||||||
|
const std::string& meshKey = meshCache.getMeshKey(dc.meshId);
|
||||||
|
vkutil::cmdBeginLabelFormatted(
|
||||||
|
cmd,
|
||||||
|
vkutil::labelColors::draw,
|
||||||
|
"%s [mesh %zu, material %u%s]",
|
||||||
|
meshKey.empty() ? "Mesh" : meshKey.c_str(),
|
||||||
|
dc.meshId,
|
||||||
|
dc.materialId,
|
||||||
|
dc.skinnedMesh != nullptr ? ", skinned" : "");
|
||||||
|
|
||||||
|
if (dc.meshId != prevMeshId)
|
||||||
|
{
|
||||||
|
prevMeshId = dc.meshId;
|
||||||
|
vkCmdBindIndexBuffer(cmd, mesh.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto pushConstants = PushConstants{
|
||||||
|
.transform = dc.transformMatrix,
|
||||||
|
.sceneDataBuffer = sceneDataBuffer.address,
|
||||||
|
.vertexBuffer =
|
||||||
|
dc.skinnedMesh != nullptr
|
||||||
|
? dc.skinnedMesh->skinnedVertexBuffer.address
|
||||||
|
: mesh.vertexBuffer.address,
|
||||||
|
.materialId = dc.materialId,
|
||||||
|
.padding = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
vkCmdPushConstants(
|
||||||
|
cmd,
|
||||||
|
m_pipelineLayout,
|
||||||
|
VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
0,
|
||||||
|
sizeof(PushConstants),
|
||||||
|
&pushConstants);
|
||||||
|
|
||||||
|
vkCmdDrawIndexed(cmd, mesh.numIndices, 1, 0, 0, 0);
|
||||||
|
|
||||||
|
vkutil::cmdEndLabel(cmd);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!sortedDrawCommands.empty())
|
||||||
|
{
|
||||||
|
for (std::size_t drawIndex : sortedDrawCommands)
|
||||||
|
{
|
||||||
|
assert(drawIndex < drawCommands.size());
|
||||||
|
drawOne(drawCommands[drawIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (const MeshDrawCommand& dc : drawCommands)
|
||||||
|
{
|
||||||
|
drawOne(dc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCmdEndRendering(cmd);
|
||||||
|
|
||||||
|
vkutil::transitionImage(
|
||||||
|
cmd,
|
||||||
|
shadowMap.image,
|
||||||
|
shadowMap.layout,
|
||||||
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
shadowMap.setLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
}
|
||||||
@@ -53,6 +53,9 @@ void SkinningPipeline::init(GfxDevice& gfxDevice) {
|
|||||||
MAX_JOINT_MATRICES * sizeof(glm::mat4),
|
MAX_JOINT_MATRICES * sizeof(glm::mat4),
|
||||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
||||||
VMA_MEMORY_USAGE_CPU_TO_GPU);
|
VMA_MEMORY_USAGE_CPU_TO_GPU);
|
||||||
|
|
||||||
|
const std::string bufferName = "joint matrices (frame " + std::to_string(i) + ")";
|
||||||
|
vkutil::addDebugLabel(device, jointMatricesBuffer.buffer.buffer, bufferName.c_str());
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
cleanup(gfxDevice);
|
cleanup(gfxDevice);
|
||||||
@@ -84,6 +87,9 @@ void SkinningPipeline::doSkinning(VkCommandBuffer cmd,
|
|||||||
assert(mesh.hasSkeleton);
|
assert(mesh.hasSkeleton);
|
||||||
assert(dc.skinnedMesh);
|
assert(dc.skinnedMesh);
|
||||||
|
|
||||||
|
const std::string& meshKey = meshCache.getMeshKey(dc.meshId);
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, meshKey.empty() ? "Skin Mesh" : meshKey.c_str(), vkutil::labelColors::compute);
|
||||||
|
|
||||||
const auto cs = PushConstants{
|
const auto cs = PushConstants{
|
||||||
.jointMatricesBuffer = getCurrentFrameData(frameIndex).jointMatricesBuffer.buffer.address,
|
.jointMatricesBuffer = getCurrentFrameData(frameIndex).jointMatricesBuffer.buffer.address,
|
||||||
.jointMatricesStartIndex = static_cast<std::uint32_t>(dc.jointMatricesStartIndex),
|
.jointMatricesStartIndex = static_cast<std::uint32_t>(dc.jointMatricesStartIndex),
|
||||||
|
|||||||
@@ -130,6 +130,8 @@ ImageID RenderResources::createImage(
|
|||||||
|
|
||||||
if (!debugName.empty()) {
|
if (!debugName.empty()) {
|
||||||
vkutil::addDebugLabel(gfxDevice.getVkDevice(), image.image, debugName.c_str());
|
vkutil::addDebugLabel(gfxDevice.getVkDevice(), image.image, debugName.c_str());
|
||||||
|
const std::string viewName = debugName + " (view)";
|
||||||
|
vkutil::addDebugLabel(gfxDevice.getVkDevice(), image.imageView, viewName.c_str());
|
||||||
image.debugName = debugName;
|
image.debugName = debugName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ void GameRenderer::init(GfxDevice& gfxDevice, RenderResources& _resources, glm::
|
|||||||
lightCullingPipeline = std::make_unique<LightCullingPipeline>();
|
lightCullingPipeline = std::make_unique<LightCullingPipeline>();
|
||||||
lightCullingPipeline->init(gfxDevice, _resources, drawImageSize);
|
lightCullingPipeline->init(gfxDevice, _resources, drawImageSize);
|
||||||
|
|
||||||
|
shadowMapPipeline = std::make_unique<ShadowMapPipeline>();
|
||||||
|
shadowMapPipeline->init(gfxDevice, _resources);
|
||||||
|
|
||||||
lineRenderingPass = std::make_unique<LineRenderingPass>();
|
lineRenderingPass = std::make_unique<LineRenderingPass>();
|
||||||
lineRenderingPass->init(gfxDevice, drawImageFormat);
|
lineRenderingPass->init(gfxDevice, drawImageFormat);
|
||||||
|
|
||||||
@@ -66,6 +69,7 @@ void GameRenderer::beginDrawing(GfxDevice& gfxDevice)
|
|||||||
meshDrawCommands.clear();
|
meshDrawCommands.clear();
|
||||||
skinningPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex());
|
skinningPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex());
|
||||||
lightCullingPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex());
|
lightCullingPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex());
|
||||||
|
shadowLightDirection.reset();
|
||||||
QuadRenderingManager::GetInstance().ClearQuads();
|
QuadRenderingManager::GetInstance().ClearQuads();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,9 +101,11 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
{
|
{
|
||||||
ZoneScopedN("GameRenderer::draw");
|
ZoneScopedN("GameRenderer::draw");
|
||||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "GameRenderer::draw");
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "GameRenderer::draw");
|
||||||
|
vkutil::ScopedCmdLabel frameLabel(cmd, "GameRenderer::draw", vkutil::labelColors::frame);
|
||||||
|
|
||||||
{
|
{
|
||||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Skinning");
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Skinning");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "Skinning", vkutil::labelColors::compute);
|
||||||
|
|
||||||
skinningPipeline->flushCurrentFrame(
|
skinningPipeline->flushCurrentFrame(
|
||||||
cmd,
|
cmd,
|
||||||
@@ -118,10 +124,17 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
|
|
||||||
{
|
{
|
||||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Lights Buffer Flush");
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Lights Buffer Flush");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "Lights Buffer Flush", vkutil::labelColors::transfer);
|
||||||
|
|
||||||
lightCullingPipeline->flushCurrentFrame(cmd, gfxDevice);
|
lightCullingPipeline->flushCurrentFrame(cmd, gfxDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const glm::mat4 lightViewProj = shadowLightDirection
|
||||||
|
? shadowMapPipeline->calculateLightViewProj(
|
||||||
|
*shadowLightDirection,
|
||||||
|
sceneData.camera.GetPosition())
|
||||||
|
: glm::mat4{1.0f};
|
||||||
|
|
||||||
// TODO: there has to be a better way to do this
|
// TODO: there has to be a better way to do this
|
||||||
const auto gpuSceneData = GPUSceneData{
|
const auto gpuSceneData = GPUSceneData{
|
||||||
.view = sceneData.camera.GetViewMatrix(),
|
.view = sceneData.camera.GetViewMatrix(),
|
||||||
@@ -139,11 +152,15 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
.numLights = lightCullingPipeline->getNumLights(),
|
.numLights = lightCullingPipeline->getNumLights(),
|
||||||
.tileCountX = lightCullingPipeline->getTileCount().x,
|
.tileCountX = lightCullingPipeline->getTileCount().x,
|
||||||
.debugLightHeatmap = renderLightHeatmap ? 1u : 0u,
|
.debugLightHeatmap = renderLightHeatmap ? 1u : 0u,
|
||||||
|
.shadowMapId = static_cast<std::uint32_t>(shadowMapPipeline->getShadowMapId()),
|
||||||
|
.shadowNormalOffset = shadowMapPipeline->getNormalOffset(),
|
||||||
.padding = 0,
|
.padding = 0,
|
||||||
|
.lightViewProj = lightViewProj,
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Material Buffer Barrier");
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Material Buffer Barrier");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "Material Buffer Barrier", vkutil::labelColors::transfer);
|
||||||
|
|
||||||
vkutil::bufferHostWriteToShaderReadBarrier(
|
vkutil::bufferHostWriteToShaderReadBarrier(
|
||||||
cmd,
|
cmd,
|
||||||
@@ -155,6 +172,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
|
|
||||||
{
|
{
|
||||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Upload Scene Data");
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Upload Scene Data");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "Upload Scene Data", vkutil::labelColors::transfer);
|
||||||
|
|
||||||
sceneDataBuffer.uploadNewData(
|
sceneDataBuffer.uploadNewData(
|
||||||
cmd,
|
cmd,
|
||||||
@@ -189,8 +207,22 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
depthImage.setLayout(VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
|
depthImage.setLayout(VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shadowLightDirection)
|
||||||
|
{
|
||||||
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Shadow Map");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "Shadow Map", vkutil::labelColors::shadow);
|
||||||
|
|
||||||
|
shadowMapPipeline->draw(
|
||||||
|
cmd,
|
||||||
|
*resources,
|
||||||
|
sceneDataBuffer.getBuffer(),
|
||||||
|
meshDrawCommands,
|
||||||
|
sortedMeshDrawCommands);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Depth Prepass");
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Depth Prepass");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "Depth Prepass", vkutil::labelColors::depth);
|
||||||
|
|
||||||
auto depthPrepassInfo = vkutil::createRenderingInfo({
|
auto depthPrepassInfo = vkutil::createRenderingInfo({
|
||||||
.renderExtent = drawImage.getExtent2D(),
|
.renderExtent = drawImage.getExtent2D(),
|
||||||
@@ -215,6 +247,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
|
|
||||||
{
|
{
|
||||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Light Culling");
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Light Culling");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "Light Culling", vkutil::labelColors::compute);
|
||||||
|
|
||||||
vkutil::transitionImage(
|
vkutil::transitionImage(
|
||||||
cmd,
|
cmd,
|
||||||
@@ -247,6 +280,8 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
renderInfo.renderingInfo.pColorAttachments = &renderInfo.colorAttachment;
|
renderInfo.renderingInfo.pColorAttachments = &renderInfo.colorAttachment;
|
||||||
renderInfo.renderingInfo.pDepthAttachment = &renderInfo.depthAttachment;
|
renderInfo.renderingInfo.pDepthAttachment = &renderInfo.depthAttachment;
|
||||||
|
|
||||||
|
vkutil::cmdBeginLabel(cmd, "Forward Pass", vkutil::labelColors::opaque);
|
||||||
|
|
||||||
{
|
{
|
||||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "vkCmdBeginRendering");
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "vkCmdBeginRendering");
|
||||||
|
|
||||||
@@ -255,6 +290,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
|
|
||||||
{
|
{
|
||||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "MeshPipeline::draw");
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "MeshPipeline::draw");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "MeshPipeline::draw", vkutil::labelColors::opaque);
|
||||||
|
|
||||||
meshPipeline->draw(
|
meshPipeline->draw(
|
||||||
cmd,
|
cmd,
|
||||||
@@ -268,6 +304,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
|
|
||||||
{
|
{
|
||||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "SkyboxPipeline::draw");
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "SkyboxPipeline::draw");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "SkyboxPipeline::draw", vkutil::labelColors::sky);
|
||||||
|
|
||||||
skyboxPipeline->draw(cmd, *resources, camera);
|
skyboxPipeline->draw(cmd, *resources, camera);
|
||||||
}
|
}
|
||||||
@@ -278,8 +315,11 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
vkCmdEndRendering(cmd);
|
vkCmdEndRendering(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vkutil::cmdEndLabel(cmd);
|
||||||
|
|
||||||
{
|
{
|
||||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "LineRenderingPass::draw");
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "LineRenderingPass::draw");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "LineRenderingPass::draw", vkutil::labelColors::debug);
|
||||||
|
|
||||||
lineRenderingPass->draw(
|
lineRenderingPass->draw(
|
||||||
cmd,
|
cmd,
|
||||||
@@ -291,6 +331,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
|
|
||||||
{
|
{
|
||||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "QuadRendererPass::draw");
|
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "QuadRendererPass::draw");
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "QuadRendererPass::draw", vkutil::labelColors::ui);
|
||||||
|
|
||||||
quadRendererPass->draw(
|
quadRendererPass->draw(
|
||||||
cmd,
|
cmd,
|
||||||
@@ -302,7 +343,6 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
|||||||
static_cast<float>(drawImage.extent.height),
|
static_cast<float>(drawImage.extent.height),
|
||||||
0.0f, -1.0f, 1.0f));
|
0.0f, -1.0f, 1.0f));
|
||||||
}
|
}
|
||||||
// vkutil::cmdEndLabel(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameRenderer::drawQuads(
|
void GameRenderer::drawQuads(
|
||||||
@@ -335,6 +375,9 @@ void GameRenderer::cleanup(GfxDevice& gfxDevice)
|
|||||||
if (lightCullingPipeline)
|
if (lightCullingPipeline)
|
||||||
lightCullingPipeline->cleanup(gfxDevice);
|
lightCullingPipeline->cleanup(gfxDevice);
|
||||||
|
|
||||||
|
if (shadowMapPipeline)
|
||||||
|
shadowMapPipeline->cleanup(device);
|
||||||
|
|
||||||
if (skyboxPipeline)
|
if (skyboxPipeline)
|
||||||
skyboxPipeline->cleanup(device);
|
skyboxPipeline->cleanup(device);
|
||||||
|
|
||||||
@@ -358,6 +401,8 @@ void GameRenderer::cleanup(GfxDevice& gfxDevice)
|
|||||||
lineRenderingPass.reset();
|
lineRenderingPass.reset();
|
||||||
quadRendererPass.reset();
|
quadRendererPass.reset();
|
||||||
lightCullingPipeline.reset();
|
lightCullingPipeline.reset();
|
||||||
|
shadowMapPipeline.reset();
|
||||||
|
shadowLightDirection.reset();
|
||||||
pendingMaterialUploads.clear();
|
pendingMaterialUploads.clear();
|
||||||
meshDrawCommands.clear();
|
meshDrawCommands.clear();
|
||||||
sortedMeshDrawCommands.clear();
|
sortedMeshDrawCommands.clear();
|
||||||
@@ -402,7 +447,18 @@ void GameRenderer::drawSkinnedMesh(MeshID id,
|
|||||||
|
|
||||||
void GameRenderer::submitLight(const Light& light)
|
void GameRenderer::submitLight(const Light& light)
|
||||||
{
|
{
|
||||||
lightCullingPipeline->appendLight(light);
|
Light submittedLight = light;
|
||||||
|
|
||||||
|
// there's a single shadow map, the first shadow casting directional light gets it
|
||||||
|
submittedLight.castShadows =
|
||||||
|
light.castShadows && light.type == LightType::Directional && !shadowLightDirection;
|
||||||
|
|
||||||
|
if (submittedLight.castShadows)
|
||||||
|
{
|
||||||
|
shadowLightDirection = light.direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
lightCullingPipeline->appendLight(submittedLight);
|
||||||
}
|
}
|
||||||
|
|
||||||
const GPUImage& GameRenderer::getDrawImage() const
|
const GPUImage& GameRenderer::getDrawImage() const
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ void CubeMap::RenderToCubemap(
|
|||||||
}
|
}
|
||||||
|
|
||||||
gfxDevice.getImmediateExecuter().immediateSubmit([&](VkCommandBuffer cmd) {
|
gfxDevice.getImmediateExecuter().immediateSubmit([&](VkCommandBuffer cmd) {
|
||||||
|
vkutil::ScopedCmdLabel label(cmd, "HDRI To Cubemap", vkutil::labelColors::sky);
|
||||||
|
|
||||||
VkImageMemoryBarrier barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
VkImageMemoryBarrier barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||||
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
@@ -108,6 +110,8 @@ void CubeMap::RenderToCubemap(
|
|||||||
scissor.extent = {size, size};
|
scissor.extent = {size, size};
|
||||||
|
|
||||||
for (std::uint32_t face = 0; face < 6; ++face) {
|
for (std::uint32_t face = 0; face < 6; ++face) {
|
||||||
|
vkutil::cmdBeginLabelFormatted(cmd, vkutil::labelColors::draw, "Cubemap Face %u", face);
|
||||||
|
|
||||||
PC pc{};
|
PC pc{};
|
||||||
pc.viewMtx = viewMatrices[face];
|
pc.viewMtx = viewMatrices[face];
|
||||||
pc.projMtx = m_projection;
|
pc.projMtx = m_projection;
|
||||||
@@ -153,6 +157,8 @@ void CubeMap::RenderToCubemap(
|
|||||||
vkCmdDraw(cmd, 36, 1, 0, 0);
|
vkCmdDraw(cmd, 36, 1, 0, 0);
|
||||||
|
|
||||||
vkCmdEndRendering(cmd);
|
vkCmdEndRendering(cmd);
|
||||||
|
|
||||||
|
vkutil::cmdEndLabel(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
@@ -199,6 +205,7 @@ void CubeMap::CreateCubeMap(
|
|||||||
.mipMap = false,
|
.mipMap = false,
|
||||||
.isCubemap = true
|
.isCubemap = true
|
||||||
});
|
});
|
||||||
|
vkutil::addDebugLabel(gfxDevice.getDevice(), cubeMapImage.image, "skybox cubemap");
|
||||||
|
|
||||||
std::array<VkImageView, 6> faceViews{};
|
std::array<VkImageView, 6> faceViews{};
|
||||||
|
|
||||||
@@ -220,6 +227,9 @@ void CubeMap::CreateCubeMap(
|
|||||||
&viewInfo,
|
&viewInfo,
|
||||||
nullptr,
|
nullptr,
|
||||||
&faceViews[face]));
|
&faceViews[face]));
|
||||||
|
|
||||||
|
const std::string faceViewName = "skybox cubemap face " + std::to_string(face) + " (view)";
|
||||||
|
vkutil::addDebugLabel(gfxDevice.getDevice(), faceViews[face], faceViewName.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
spdlog::info("HDRI image id = {}", m_hdrImage);
|
spdlog::info("HDRI image id = {}", m_hdrImage);
|
||||||
@@ -305,6 +315,7 @@ void CubeMap::InitCubemapPipeline(
|
|||||||
|
|
||||||
PipelineConfigInfo pipelineConfig{};
|
PipelineConfigInfo pipelineConfig{};
|
||||||
Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
|
Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
|
||||||
|
pipelineConfig.name = "HDRI To Cubemap Pipeline";
|
||||||
|
|
||||||
pipelineConfig.vertexAttributeDescriptions = {};
|
pipelineConfig.vertexAttributeDescriptions = {};
|
||||||
pipelineConfig.vertexBindingDescriptions = {};
|
pipelineConfig.vertexBindingDescriptions = {};
|
||||||
|
|||||||
@@ -21,6 +21,22 @@ void Swapchain::initSync(VkDevice device) {
|
|||||||
for (std::uint32_t i = 0; i < FRAMES_IN_FLIGHT; ++i) {
|
for (std::uint32_t i = 0; i < FRAMES_IN_FLIGHT; ++i) {
|
||||||
VK_CHECK(vkCreateFence(device, &fenceCreateInfo, nullptr, &frames[i].renderFence));
|
VK_CHECK(vkCreateFence(device, &fenceCreateInfo, nullptr, &frames[i].renderFence));
|
||||||
VK_CHECK(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &frames[i].swapchainSemaphore));
|
VK_CHECK(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &frames[i].swapchainSemaphore));
|
||||||
|
|
||||||
|
const auto fenceName = std::format("frame {} render fence", i);
|
||||||
|
const auto semaphoreName = std::format("frame {} swapchain semaphore", i);
|
||||||
|
vkutil::addDebugLabel(device, frames[i].renderFence, fenceName.c_str());
|
||||||
|
vkutil::addDebugLabel(device, frames[i].swapchainSemaphore, semaphoreName.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Swapchain::nameSwapchainObjects(VkDevice device) const {
|
||||||
|
for (std::size_t i = 0; i < images.size(); ++i) {
|
||||||
|
const auto imageName = std::format("swapchain image {}", i);
|
||||||
|
const auto viewName = std::format("swapchain image {} (view)", i);
|
||||||
|
const auto semaphoreName = std::format("swapchain image {} render semaphore", i);
|
||||||
|
vkutil::addDebugLabel(device, images[i], imageName.c_str());
|
||||||
|
vkutil::addDebugLabel(device, imageViews[i], viewName.c_str());
|
||||||
|
vkutil::addDebugLabel(device, imageRenderSemaphores[i], semaphoreName.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,6 +101,8 @@ void Swapchain::createSwapchain(
|
|||||||
VK_CHECK(vkCreateSemaphore(vkbDevice, &sci, nullptr, &sem));
|
VK_CHECK(vkCreateSemaphore(vkbDevice, &sci, nullptr, &sem));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nameSwapchainObjects(vkbDevice);
|
||||||
|
|
||||||
extent = m_swapchain.extent;
|
extent = m_swapchain.extent;
|
||||||
dirty = false;
|
dirty = false;
|
||||||
}
|
}
|
||||||
@@ -187,6 +205,8 @@ void Swapchain::recreateSwapchain(
|
|||||||
VK_CHECK(vkCreateSemaphore(vkbDevice, &sci, nullptr, &sem));
|
VK_CHECK(vkCreateSemaphore(vkbDevice, &sci, nullptr, &sem));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nameSwapchainObjects(vkbDevice);
|
||||||
|
|
||||||
extent = m_swapchain.extent;
|
extent = m_swapchain.extent;
|
||||||
dirty = false;
|
dirty = false;
|
||||||
}
|
}
|
||||||
|
|||||||
+101
-101
@@ -188,54 +188,124 @@ void vkutil::bufferHostWriteToTransferReadBarrier(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void vkutil::addDebugLabel(VkDevice device, VkImage image, const char* label) {
|
void vkutil::addDebugLabel(VkDevice device, VkObjectType objectType, std::uint64_t objectHandle, const char* label) {
|
||||||
|
if (!vkSetDebugUtilsObjectNameEXT || device == VK_NULL_HANDLE || objectHandle == 0 || label == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||||
.objectType = VK_OBJECT_TYPE_IMAGE,
|
.objectType = objectType,
|
||||||
.objectHandle = (std::uint64_t)image,
|
.objectHandle = objectHandle,
|
||||||
.pObjectName = label,
|
.pObjectName = label,
|
||||||
};
|
};
|
||||||
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vkutil::addDebugLabel(VkDevice device, VkImage image, const char* label) {
|
||||||
|
addDebugLabel(device, VK_OBJECT_TYPE_IMAGE, reinterpret_cast<std::uint64_t>(image), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vkutil::addDebugLabel(VkDevice device, VkImageView imageView, const char* label) {
|
||||||
|
addDebugLabel(device, VK_OBJECT_TYPE_IMAGE_VIEW, reinterpret_cast<std::uint64_t>(imageView), label);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vkutil::addDebugLabel(VkDevice device, VkShaderModule shaderModule, const char* label) {
|
void vkutil::addDebugLabel(VkDevice device, VkShaderModule shaderModule, const char* label) {
|
||||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
addDebugLabel(device, VK_OBJECT_TYPE_SHADER_MODULE, reinterpret_cast<std::uint64_t>(shaderModule), label);
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
|
||||||
.objectType = VK_OBJECT_TYPE_SHADER_MODULE,
|
|
||||||
.objectHandle = (std::uint64_t)shaderModule,
|
|
||||||
.pObjectName = label,
|
|
||||||
};
|
|
||||||
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vkutil::addDebugLabel(VkDevice device, VkPipeline pipeline, const char* label) {
|
void vkutil::addDebugLabel(VkDevice device, VkPipeline pipeline, const char* label) {
|
||||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
addDebugLabel(device, VK_OBJECT_TYPE_PIPELINE, reinterpret_cast<std::uint64_t>(pipeline), label);
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
}
|
||||||
.objectType = VK_OBJECT_TYPE_PIPELINE,
|
|
||||||
.objectHandle = (std::uint64_t)pipeline,
|
void vkutil::addDebugLabel(VkDevice device, VkPipelineLayout layout, const char* label) {
|
||||||
.pObjectName = label,
|
addDebugLabel(device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, reinterpret_cast<std::uint64_t>(layout), label);
|
||||||
};
|
|
||||||
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vkutil::addDebugLabel(VkDevice device, VkBuffer buffer, const char* label) {
|
void vkutil::addDebugLabel(VkDevice device, VkBuffer buffer, const char* label) {
|
||||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
addDebugLabel(device, VK_OBJECT_TYPE_BUFFER, reinterpret_cast<std::uint64_t>(buffer), label);
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
|
||||||
.objectType = VK_OBJECT_TYPE_BUFFER,
|
|
||||||
.objectHandle = (std::uint64_t)buffer,
|
|
||||||
.pObjectName = label,
|
|
||||||
};
|
|
||||||
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vkutil::addDebugLabel(VkDevice device, VkSampler sampler, const char* label) {
|
void vkutil::addDebugLabel(VkDevice device, VkSampler sampler, const char* label) {
|
||||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
addDebugLabel(device, VK_OBJECT_TYPE_SAMPLER, reinterpret_cast<std::uint64_t>(sampler), label);
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
}
|
||||||
.objectType = VK_OBJECT_TYPE_SAMPLER,
|
|
||||||
.objectHandle = (std::uint64_t)sampler,
|
void vkutil::addDebugLabel(VkDevice device, VkDescriptorPool descriptorPool, const char* label) {
|
||||||
.pObjectName = label,
|
addDebugLabel(device, VK_OBJECT_TYPE_DESCRIPTOR_POOL, reinterpret_cast<std::uint64_t>(descriptorPool), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vkutil::addDebugLabel(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const char* label) {
|
||||||
|
addDebugLabel(device, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, reinterpret_cast<std::uint64_t>(descriptorSetLayout), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vkutil::addDebugLabel(VkDevice device, VkDescriptorSet descriptorSet, const char* label) {
|
||||||
|
addDebugLabel(device, VK_OBJECT_TYPE_DESCRIPTOR_SET, reinterpret_cast<std::uint64_t>(descriptorSet), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vkutil::addDebugLabel(VkDevice device, VkCommandPool commandPool, const char* label) {
|
||||||
|
addDebugLabel(device, VK_OBJECT_TYPE_COMMAND_POOL, reinterpret_cast<std::uint64_t>(commandPool), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vkutil::addDebugLabel(VkDevice device, VkCommandBuffer commandBuffer, const char* label) {
|
||||||
|
addDebugLabel(device, VK_OBJECT_TYPE_COMMAND_BUFFER, reinterpret_cast<std::uint64_t>(commandBuffer), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vkutil::addDebugLabel(VkDevice device, VkFence fence, const char* label) {
|
||||||
|
addDebugLabel(device, VK_OBJECT_TYPE_FENCE, reinterpret_cast<std::uint64_t>(fence), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vkutil::addDebugLabel(VkDevice device, VkSemaphore semaphore, const char* label) {
|
||||||
|
addDebugLabel(device, VK_OBJECT_TYPE_SEMAPHORE, reinterpret_cast<std::uint64_t>(semaphore), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vkutil::addDebugLabel(VkDevice device, VkQueue queue, const char* label) {
|
||||||
|
addDebugLabel(device, VK_OBJECT_TYPE_QUEUE, reinterpret_cast<std::uint64_t>(queue), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vkutil::debugLabelsEnabled() {
|
||||||
|
return vkCmdBeginDebugUtilsLabelEXT != nullptr && vkCmdEndDebugUtilsLabelEXT != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vkutil::cmdBeginLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color) {
|
||||||
|
if (!debugLabelsEnabled() || label == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto labelInfo = VkDebugUtilsLabelEXT{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
|
||||||
|
.pLabelName = label,
|
||||||
|
.color = {color.x, color.y, color.z, color.w},
|
||||||
};
|
};
|
||||||
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
vkCmdBeginDebugUtilsLabelEXT(cmd, &labelInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vkutil::cmdEndLabel(VkCommandBuffer cmd) {
|
||||||
|
if (!debugLabelsEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vkCmdEndDebugUtilsLabelEXT(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vkutil::cmdInsertLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color) {
|
||||||
|
if (!vkCmdInsertDebugUtilsLabelEXT || label == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto labelInfo = VkDebugUtilsLabelEXT{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
|
||||||
|
.pLabelName = label,
|
||||||
|
.color = {color.x, color.y, color.z, color.w},
|
||||||
|
};
|
||||||
|
vkCmdInsertDebugUtilsLabelEXT(cmd, &labelInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkutil::ScopedCmdLabel::ScopedCmdLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color)
|
||||||
|
: cmd(cmd) {
|
||||||
|
cmdBeginLabel(cmd, label, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkutil::ScopedCmdLabel::~ScopedCmdLabel() {
|
||||||
|
cmdEndLabel(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
vkutil::RenderInfo vkutil::createRenderingInfo(const RenderingInfoParams& params) {
|
vkutil::RenderInfo vkutil::createRenderingInfo(const RenderingInfoParams& params) {
|
||||||
@@ -319,76 +389,6 @@ VkShaderModule vkutil::loadShaderModule(const std::filesystem::path& path, VkDev
|
|||||||
return shaderModule;
|
return shaderModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addDebugLabel(VkDevice device, VkImage image, const char* label) {
|
|
||||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
|
||||||
.objectType = VK_OBJECT_TYPE_IMAGE,
|
|
||||||
.objectHandle = (std::uint64_t)image,
|
|
||||||
.pObjectName = label,
|
|
||||||
};
|
|
||||||
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addDebugLabel(VkDevice device, VkImageView imageView, const char* label) {
|
|
||||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
|
||||||
.objectType = VK_OBJECT_TYPE_IMAGE_VIEW,
|
|
||||||
.objectHandle = (std::uint64_t)imageView,
|
|
||||||
.pObjectName = label,
|
|
||||||
};
|
|
||||||
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addDebugLabel(VkDevice device, VkShaderModule shaderModule, const char* label) {
|
|
||||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
|
||||||
.objectType = VK_OBJECT_TYPE_SHADER_MODULE,
|
|
||||||
.objectHandle = (std::uint64_t)shaderModule,
|
|
||||||
.pObjectName = label,
|
|
||||||
};
|
|
||||||
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addDebugLabel(VkDevice device, VkPipeline pipeline, const char* label) {
|
|
||||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
|
||||||
.objectType = VK_OBJECT_TYPE_PIPELINE,
|
|
||||||
.objectHandle = (std::uint64_t)pipeline,
|
|
||||||
.pObjectName = label,
|
|
||||||
};
|
|
||||||
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addDebugLabel(VkDevice device, VkPipelineLayout layout, const char* label) {
|
|
||||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
|
||||||
.objectType = VK_OBJECT_TYPE_PIPELINE_LAYOUT,
|
|
||||||
.objectHandle = (std::uint64_t)layout,
|
|
||||||
.pObjectName = label,
|
|
||||||
};
|
|
||||||
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addDebugLabel(VkDevice device, VkBuffer buffer, const char* label) {
|
|
||||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
|
||||||
.objectType = VK_OBJECT_TYPE_BUFFER,
|
|
||||||
.objectHandle = (std::uint64_t)buffer,
|
|
||||||
.pObjectName = label,
|
|
||||||
};
|
|
||||||
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addDebugLabel(VkDevice device, VkSampler sampler, const char* label) {
|
|
||||||
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
|
||||||
.objectType = VK_OBJECT_TYPE_SAMPLER,
|
|
||||||
.objectHandle = (std::uint64_t)sampler,
|
|
||||||
.pObjectName = label,
|
|
||||||
};
|
|
||||||
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
vkutil::RenderInfo createRenderingInfo(const vkutil::RenderingInfoParams& params) {
|
vkutil::RenderInfo createRenderingInfo(const vkutil::RenderingInfoParams& params) {
|
||||||
return vkutil::createRenderingInfo(params);
|
return vkutil::createRenderingInfo(params);
|
||||||
}
|
}
|
||||||
|
|||||||
+110
-98
@@ -153,65 +153,65 @@ void LightKeeper::customInit()
|
|||||||
characterModelOptions.loadSkeleton = true;
|
characterModelOptions.loadSkeleton = true;
|
||||||
characterModelOptions.loadAnimations = true;
|
characterModelOptions.loadAnimations = true;
|
||||||
|
|
||||||
// auto charModel = ModelDoc::LoadModel(
|
auto charModel = ModelDoc::LoadModel(
|
||||||
// AssetFS::GetInstance().GetFullPath("engine://cotw-capybara-male/source/capybara.fbx").generic_string(),
|
AssetFS::GetInstance().GetFullPath("engine://cotw-capybara-male/source/capybara.fbx").generic_string(),
|
||||||
// characterModelOptions
|
characterModelOptions
|
||||||
// );
|
);
|
||||||
// ModelDocUtils::LogModelDocSummary(charModel, "capybara.fbx");
|
ModelDocUtils::LogModelDocSummary(charModel, "capybara.fbx");
|
||||||
//
|
|
||||||
// const auto& charPrimitive = ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow(
|
const auto& charPrimitive = ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow(
|
||||||
// charModel,
|
charModel,
|
||||||
// "engine://cotw-capybara-male/source/capybara.fbx"
|
"engine://cotw-capybara-male/source/capybara.fbx"
|
||||||
// );
|
);
|
||||||
//
|
|
||||||
// const auto charMeshID = resources.meshes().addMesh(gfxDevice, charPrimitive.mesh);
|
const auto charMeshID = resources.meshes().addMesh(gfxDevice, charPrimitive.mesh);
|
||||||
//
|
|
||||||
// const auto charTexturePath = ModelDocUtils::PickTexturePath(
|
const auto charTexturePath = ModelDocUtils::PickTexturePath(
|
||||||
// charModel,
|
charModel,
|
||||||
// charPrimitive,
|
charPrimitive,
|
||||||
// AssetFS::GetInstance().GetFullPath(
|
AssetFS::GetInstance().GetFullPath(
|
||||||
// "engine://cotw-capybara-male/textures/capybara_male_light_brown_dif.ddsc.DECA.RE.pngballs")
|
"engine://cotw-capybara-male/textures/capybara_male_light_brown_dif.ddsc.DECA.RE.pngballs")
|
||||||
// );
|
);
|
||||||
//
|
|
||||||
// const auto charTextureID = resources.loadImageFromFile(gfxDevice, charTexturePath);
|
const auto charTextureID = resources.loadImageFromFile(gfxDevice, charTexturePath);
|
||||||
// // const auto charTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("engine://char.jpg"));
|
// const auto charTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("engine://char.jpg"));
|
||||||
// const auto charMaterialID = resources.materials().addMaterial({
|
const auto charMaterialID = resources.materials().addMaterial({
|
||||||
// .baseColor = ModelDocUtils::GetImportedBaseColor(
|
.baseColor = ModelDocUtils::GetImportedBaseColor(
|
||||||
// charModel, charPrimitive),
|
charModel, charPrimitive),
|
||||||
// .diffuseTexture = charTextureID,
|
.diffuseTexture = charTextureID,
|
||||||
// .name = ModelDocUtils::GetImportedMaterialName(
|
.name = ModelDocUtils::GetImportedMaterialName(
|
||||||
// charModel, charPrimitive, "CharacterMaterial"),
|
charModel, charPrimitive, "CharacterMaterial"),
|
||||||
// });
|
});
|
||||||
//
|
|
||||||
// const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
|
const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
|
||||||
// charMeshComp->SetMeshID(charMeshID);
|
charMeshComp->SetMeshID(charMeshID);
|
||||||
// charMeshComp->SetMaterialID(charMaterialID);
|
charMeshComp->SetMaterialID(charMaterialID);
|
||||||
//
|
|
||||||
// const auto animator = CharObj->AddComponent<Animator>();
|
const auto animator = CharObj->AddComponent<Animator>();
|
||||||
// animator->setSkeleton(std::move(charModel.skeleton));
|
animator->setSkeleton(std::move(charModel.skeleton));
|
||||||
//
|
|
||||||
// std::string firstAnimationName;
|
std::string firstAnimationName;
|
||||||
//
|
|
||||||
// for (auto& clip : charModel.animations)
|
for (auto& clip : charModel.animations)
|
||||||
// {
|
{
|
||||||
// spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
|
spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
|
||||||
//
|
|
||||||
// if (firstAnimationName.empty())
|
if (firstAnimationName.empty())
|
||||||
// firstAnimationName = clip.name;
|
firstAnimationName = clip.name;
|
||||||
//
|
|
||||||
// animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
|
animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// if (!firstAnimationName.empty())
|
if (!firstAnimationName.empty())
|
||||||
// {
|
{
|
||||||
// spdlog::info("Playing animation: '{}'", firstAnimationName);
|
spdlog::info("Playing animation: '{}'", firstAnimationName);
|
||||||
// animator->play(firstAnimationName);
|
animator->play(firstAnimationName);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// animator->play("capybara_canter_fwd_01|capybara_canter_fwd_01|run");
|
animator->play("capybara_canter_fwd_01|capybara_canter_fwd_01|run");
|
||||||
//
|
|
||||||
// CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f, 0.f, 0.f));
|
CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f, 0.f, 0.f));
|
||||||
// CharObj->GetTransform().SetWorldScale(0.01f, 0.01f, 0.01f);
|
CharObj->GetTransform().SetWorldScale(0.01f, 0.01f, 0.01f);
|
||||||
|
|
||||||
// ModelDoc::LoadOptions options{};
|
// ModelDoc::LoadOptions options{};
|
||||||
// options.meshImportMode = ModelDoc::MeshImportMode::MergedPerNode;
|
// options.meshImportMode = ModelDoc::MeshImportMode::MergedPerNode;
|
||||||
@@ -450,46 +450,58 @@ void LightKeeper::customInit()
|
|||||||
triggerObj->GetTransform().SetWorldPosition({0.0f, 0.0f, 0.0f});
|
triggerObj->GetTransform().SetWorldPosition({0.0f, 0.0f, 0.0f});
|
||||||
|
|
||||||
// Forward+ test lights: a dim sun and a ring of colored point lights orbiting the origin
|
// Forward+ test lights: a dim sun and a ring of colored point lights orbiting the origin
|
||||||
auto sunObj = scene.CreateGameObject("Sun");
|
// auto sunObj = scene.CreateGameObject("Sun");
|
||||||
auto* sun = sunObj->AddComponent<LightComponent>(LightType::Directional);
|
// auto* sun = sunObj->AddComponent<LightComponent>(LightType::Directional);
|
||||||
sun->SetColor(glm::vec3{1.0f, 0.95f, 0.85f});
|
// sun->SetColor(glm::vec3{1.0f, 0.95f, 0.85f});
|
||||||
sun->SetIntensity(1.0f);
|
// sun->SetIntensity(1.0f);
|
||||||
sunObj->GetTransform().SetWorldRotation(glm::vec3{-50.0f, 30.0f, 0.0f});
|
// sun->SetCastShadows(true);
|
||||||
|
// sunObj->GetTransform().SetWorldRotation(glm::vec3{-50.0f, 30.0f, 0.0f});
|
||||||
|
//
|
||||||
|
// // static shadow casters, so the sun's shadows are visible without spawning balls
|
||||||
|
// for (int i = 0; i < 3; i++)
|
||||||
|
// {
|
||||||
|
// auto casterObj = scene.CreateGameObject("ShadowCaster " + std::to_string(i));
|
||||||
|
// auto* casterMesh = casterObj->AddComponent<MeshRendererComponent>();
|
||||||
|
// casterMesh->SetMeshID(sphereMesh);
|
||||||
|
// casterMesh->SetMaterialID(sphereMaterial);
|
||||||
|
// casterObj->GetTransform().SetWorldPosition(glm::vec3{-4.0f + 4.0f * static_cast<float>(i), 0.5f, 3.0f});
|
||||||
|
// casterObj->GetTransform().SetWorldScale(glm::vec3{0.015f});
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// constexpr int pointLightCount = 32;
|
||||||
|
// constexpr float pointLightRingRadius = 6.0f;
|
||||||
|
// for (int i = 0; i < pointLightCount; i++)
|
||||||
|
// {
|
||||||
|
// const float t = static_cast<float>(i) / static_cast<float>(pointLightCount);
|
||||||
|
// const float angle = t * glm::two_pi<float>();
|
||||||
|
//
|
||||||
|
// auto lightObj = scene.CreateGameObject("PointLight " + std::to_string(i));
|
||||||
|
// lightObj->GetTransform().SetWorldPosition(glm::vec3{
|
||||||
|
// std::cos(angle) * pointLightRingRadius,
|
||||||
|
// -0.25f,
|
||||||
|
// std::sin(angle) * pointLightRingRadius
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// auto* light = lightObj->AddComponent<LightComponent>(LightType::Point);
|
||||||
|
// light->SetColor(glm::vec3{
|
||||||
|
// 0.5f + 0.5f * std::cos(glm::two_pi<float>() * t),
|
||||||
|
// 0.5f + 0.5f * std::cos(glm::two_pi<float>() * (t + 0.33f)),
|
||||||
|
// 0.5f + 0.5f * std::cos(glm::two_pi<float>() * (t + 0.67f))
|
||||||
|
// });
|
||||||
|
// light->SetIntensity(1.0f);
|
||||||
|
// light->SetRange(3.0f);
|
||||||
|
//
|
||||||
|
// auto* orbit = lightObj->AddComponent<Rotator>(pointLightRingRadius, 0.5f);
|
||||||
|
// orbit->SetAxis(glm::vec3{0.0f, 1.0f, 0.0f});
|
||||||
|
// orbit->SetPivotPosition(glm::vec3{0.0f, -0.25f, 0.0f});
|
||||||
|
// }
|
||||||
|
|
||||||
constexpr int pointLightCount = 32;
|
// auto playerObj = scene.CreateGameObject("Player");
|
||||||
constexpr float pointLightRingRadius = 6.0f;
|
// playerObj->GetTransform().SetWorldPosition(glm::vec3(0.0f, 2.0f, -5.0f));
|
||||||
for (int i = 0; i < pointLightCount; i++)
|
// auto* fps = playerObj->AddComponent<FirstPersonController>();
|
||||||
{
|
// m_Player = playerObj;
|
||||||
const float t = static_cast<float>(i) / static_cast<float>(pointLightCount);
|
// m_FPSController = fps;
|
||||||
const float angle = t * glm::two_pi<float>();
|
// scene.GetPhysics().RegisterGameObject(*playerObj);
|
||||||
|
|
||||||
auto lightObj = scene.CreateGameObject("PointLight " + std::to_string(i));
|
|
||||||
lightObj->GetTransform().SetWorldPosition(glm::vec3{
|
|
||||||
std::cos(angle) * pointLightRingRadius,
|
|
||||||
-0.25f,
|
|
||||||
std::sin(angle) * pointLightRingRadius
|
|
||||||
});
|
|
||||||
|
|
||||||
auto* light = lightObj->AddComponent<LightComponent>(LightType::Point);
|
|
||||||
light->SetColor(glm::vec3{
|
|
||||||
0.5f + 0.5f * std::cos(glm::two_pi<float>() * t),
|
|
||||||
0.5f + 0.5f * std::cos(glm::two_pi<float>() * (t + 0.33f)),
|
|
||||||
0.5f + 0.5f * std::cos(glm::two_pi<float>() * (t + 0.67f))
|
|
||||||
});
|
|
||||||
light->SetIntensity(1.0f);
|
|
||||||
light->SetRange(3.0f);
|
|
||||||
|
|
||||||
auto* orbit = lightObj->AddComponent<Rotator>(pointLightRingRadius, 0.5f);
|
|
||||||
orbit->SetAxis(glm::vec3{0.0f, 1.0f, 0.0f});
|
|
||||||
orbit->SetPivotPosition(glm::vec3{0.0f, -0.25f, 0.0f});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto playerObj = scene.CreateGameObject("Player");
|
|
||||||
playerObj->GetTransform().SetWorldPosition(glm::vec3(0.0f, 2.0f, -5.0f));
|
|
||||||
auto* fps = playerObj->AddComponent<FirstPersonController>();
|
|
||||||
m_Player = playerObj;
|
|
||||||
m_FPSController = fps;
|
|
||||||
scene.GetPhysics().RegisterGameObject(*playerObj);
|
|
||||||
|
|
||||||
const auto texPath = AssetFS::GetInstance().GetFullPath("engine://textures/kobe.png");
|
const auto texPath = AssetFS::GetInstance().GetFullPath("engine://textures/kobe.png");
|
||||||
texID = resources.loadImageFromFile(gfxDevice, texPath);
|
texID = resources.loadImageFromFile(gfxDevice, texPath);
|
||||||
|
|||||||
@@ -457,6 +457,7 @@ namespace {
|
|||||||
light->SetIntensity(4.0f);
|
light->SetIntensity(4.0f);
|
||||||
light->SetRange(7.5f);
|
light->SetRange(7.5f);
|
||||||
light->SetConeAngles(0.2f, 0.4f);
|
light->SetConeAngles(0.2f, 0.4f);
|
||||||
|
light->SetCastShadows(true);
|
||||||
|
|
||||||
const auto data = light->Serialize();
|
const auto data = light->Serialize();
|
||||||
|
|
||||||
@@ -472,6 +473,8 @@ namespace {
|
|||||||
"LightComponent must round-trip intensity and range");
|
"LightComponent must round-trip intensity and range");
|
||||||
check(loaded->GetInnerConeAngle() == 0.2f && loaded->GetOuterConeAngle() == 0.4f,
|
check(loaded->GetInnerConeAngle() == 0.2f && loaded->GetOuterConeAngle() == 0.4f,
|
||||||
"LightComponent must round-trip its cone angles");
|
"LightComponent must round-trip its cone angles");
|
||||||
|
check(loaded->GetCastShadows(),
|
||||||
|
"LightComponent must round-trip its cast shadows flag");
|
||||||
|
|
||||||
loaded->SetConeAngles(0.5f, 0.1f);
|
loaded->SetConeAngles(0.5f, 0.1f);
|
||||||
check(loaded->GetOuterConeAngle() >= loaded->GetInnerConeAngle(),
|
check(loaded->GetOuterConeAngle() >= loaded->GetInnerConeAngle(),
|
||||||
|
|||||||
Reference in New Issue
Block a user