feat: basic shadow map + renderdoc labels

This commit is contained in:
2026-10-11 01:02:26 +02:00
parent 4bf87bd91b
commit 95d1497169
36 changed files with 880 additions and 228 deletions
+1
View File
@@ -50,6 +50,7 @@ set(SRC_FILES
"src/Graphics/Pipelines/QuadRendererPass.cpp"
"src/Graphics/Pipelines/SkyboxPipeline.cpp"
"src/Graphics/Pipelines/LightCullingPipeline.cpp"
"src/Graphics/Pipelines/ShadowMapPipeline.cpp"
"src/Graphics/Pipelines/SkinningPipeline.cpp"
"src/Graphics/Pipelines/ImguiPass.cpp"
+4
View File
@@ -35,6 +35,10 @@ vec4 sampleTextureCubeLinear(uint texID, vec3 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) {
return texture(nonuniformEXT(sampler2DArrayShadow(textureArrays[texID], samplers[SHADOW_SAMPLER_ID])), p);
}
+2 -2
View File
@@ -44,7 +44,7 @@ float calculateSpotAttenuation(Light light, vec3 l)
}
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;
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 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
+2 -1
View File
@@ -27,7 +27,8 @@ struct Light {
float spotInnerCos;
float spotOuterCos;
vec2 padding;
uint castShadows;
float padding;
};
layout (buffer_reference, std430) readonly buffer LightsBuffer {
+11 -1
View File
@@ -6,6 +6,7 @@
#include "scene_data.glsl"
#include "mesh_pcs.glsl"
#include "lighting.glsl"
#include "shadows.glsl"
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUV;
@@ -69,8 +70,17 @@ void main()
uint lightIndex = pcs.sceneData.tileLightIndices.data[tileOffset + 1 + i];
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,
diffuseColor, roughness, metallic, f0);
diffuseColor, roughness, metallic, f0, occlusion);
}
// emissive
@@ -33,7 +33,12 @@ layout (buffer_reference, scalar) readonly buffer SceneDataBuffer {
uint numLights;
uint tileCountX;
uint debugLightHeatmap;
// directional shadows
uint shadowMapId;
float shadowNormalOffset;
uint padding;
mat4 lightViewProj;
} sceneDataBuffer;
#endif // SCENE_DATA_GLSL
+12
View File
@@ -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);
}
+34
View File
@@ -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 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
+5 -1
View File
@@ -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};
+61
View File
@@ -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;
+10 -1
View File
@@ -47,6 +47,7 @@ void LightComponent::Render(const RenderContext& ctx)
.range = m_Range,
.innerConeAngle = m_InnerConeAngle,
.outerConeAngle = m_OuterConeAngle,
.castShadows = m_CastShadows,
});
}
@@ -57,7 +58,8 @@ nlohmann::json LightComponent::Serialize() const {
{"intensity", m_Intensity},
{"range", m_Range},
{"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>();
}
SetConeAngles(innerConeAngle, outerConeAngle);
if (data.contains("castShadows")) {
m_CastShadows = data.at("castShadows").get<bool>();
}
}
void LightComponent::ImGuiInspector() {
@@ -106,6 +112,9 @@ void LightComponent::ImGuiInspector() {
}
if (m_Type == LightType::Directional) {
ImGui::Checkbox("Cast Shadows", &m_CastShadows);
ImGui::SameLine();
ImGui::TextDisabled("(first directional light only)");
return;
}
@@ -33,6 +33,9 @@ void MeshRendererComponent::Start() {
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_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));
vkutil::addDebugLabel(device, descPool, "bindless descriptor pool");
}
{ // build desc set layout
@@ -111,6 +112,7 @@ void BindlessSetManager::init(
};
VK_CHECK(vkCreateDescriptorSetLayout(device, &info, nullptr, &descSetLayout));
vkutil::addDebugLabel(device, descSetLayout, "bindless descriptor set layout");
}
{ // alloc desc set
@@ -122,6 +124,7 @@ void BindlessSetManager::init(
};
VK_CHECK(vkAllocateDescriptorSets(device, &allocInfo, &descSet));
vkutil::addDebugLabel(device, descSet, "bindless descriptor set");
}
initDefaultSamplers(device, maxAnisotropy);
+6 -1
View File
@@ -99,8 +99,13 @@ void ComputePipeline::CreateComputePipeline(const std::string& compPath,
throw std::runtime_error("Can't make compute pipeline!");
}
vkutil::addDebugLabel(m_device.getDevice(), m_compShaderModule, compFileName.c_str());
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());
}
}
+4
View File
@@ -156,6 +156,7 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
auto swapchainLayout = VK_IMAGE_LAYOUT_UNDEFINED; {
ZoneScopedN("Clear Swapchain Image");
vkutil::ScopedCmdLabel label(cmd, "Clear Swapchain Image", vkutil::labelColors::transfer);
const VkImageSubresourceRange clearRange = vkinit::imageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
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) {
ZoneScopedN("Copy DrawImage To Swapchain");
vkutil::ScopedCmdLabel label(cmd, "Copy DrawImage To Swapchain", vkutil::labelColors::transfer);
vkutil::transitionImage(
cmd,
@@ -190,6 +192,7 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
if (props.imguiPass) {
ZoneScopedN("ImGui Render");
vkutil::ScopedCmdLabel label(cmd, "ImGui Render", vkutil::labelColors::ui);
props.imguiPass->render(
cmd,
@@ -202,6 +205,7 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
{
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);
swapchainLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
@@ -40,6 +40,10 @@ void VulkanImmediateExecutor::init(
};
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;
} catch (...) {
cleanup(deviceHandle);
@@ -26,6 +26,11 @@ void FrameManager::init(VkDevice dev, std::uint32_t queueFamily) {
const auto cmdAllocInfo = vkinit::commandBufferAllocateInfo(commandPool, 1);
auto& mainCommandBuffer = frames[i].commandBuffer;
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 (...) {
cleanup(dev);
@@ -178,7 +178,9 @@ std::optional<GPUImage> ImageManager::loadImageFromFile(
}
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;
}
+3
View File
@@ -156,6 +156,9 @@ void MeshCache::uploadMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh, GPUMesh
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
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 =
gfxDevice.createBuffer(
skinningDataSize,
+17 -18
View File
@@ -146,11 +146,11 @@ void Pipeline::CreateGraphicsPipeline(const std::string& vertPath, const std::st
CreateShaderModule(vertCode, &m_vertShaderModule);
// vkutil::addDebugLabel(
// m_device.getDevice(),
// m_fragShaderModule,
// VertFileName.c_str()
// );
vkutil::addDebugLabel(
m_device.getDevice(),
m_vertShaderModule,
VertFileName.c_str()
);
VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
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);
// vkutil::addDebugLabel(
// m_device.getDevice(),
// m_fragShaderModule,
// FragFileName.c_str()
// );
vkutil::addDebugLabel(
m_device.getDevice(),
m_fragShaderModule,
FragFileName.c_str()
);
VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
@@ -231,18 +231,17 @@ void Pipeline::CreateGraphicsPipeline(const std::string& vertPath, const std::st
pipelineInfo.basePipelineIndex = -1;
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) {
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 {
@@ -158,7 +158,8 @@ void LightCullingPipeline::appendLight(const Light& light)
.type = static_cast<std::uint32_t>(light.type),
.spotInnerCos = std::cos(light.innerConeAngle),
.spotOuterCos = std::cos(light.outerConeAngle),
.padding = glm::vec2{0.0f},
.castShadows = light.castShadows ? 1u : 0u,
.padding = 0.0f,
};
lightsBuffer.append(gpuLight);
}
@@ -9,6 +9,7 @@
#include <destrum/Graphics/RenderResources.h>
#include <destrum/Graphics/Caches/MeshCache.h>
#include <destrum/Graphics/Frustum.h>
#include <destrum/Graphics/Util.h>
#include "volk.h"
#include "spdlog/spdlog.h"
@@ -219,6 +220,16 @@ void MeshPipeline::drawMeshes(
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;
@@ -254,6 +265,8 @@ void MeshPipeline::drawMeshes(
);
vkCmdDrawIndexed(cmd, mesh.numIndices, 1, 0, 0, 0);
vkutil::cmdEndLabel(cmd);
};
if (!sortedDrawCommands.empty())
@@ -42,12 +42,14 @@ void QuadRendererPass::init(GfxDevice& gfxDevice, RenderResources& resources, Vk
vertexBytes,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
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);
indexBuffer = gfxDevice.createBuffer(
indexBytes,
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
vkutil::addDebugLabel(gfxDevice.getDevice(), indexBuffer.buffer, "quad indices");
quadCapacity = InitialQuadCapacity;
@@ -321,6 +323,7 @@ void QuadRendererPass::ensureCapacity(
newCapacity * VerticesPerQuad * sizeof(QuadVertex),
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
vkutil::addDebugLabel(gfxDevice.getDevice(), vertexBuffer.buffer, "quad vertices");
if (indexBuffer.buffer != VK_NULL_HANDLE) {
gfxDevice.destroyBuffer(indexBuffer);
@@ -329,6 +332,7 @@ void QuadRendererPass::ensureCapacity(
newCapacity * IndicesPerQuad * sizeof(std::uint32_t),
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
vkutil::addDebugLabel(gfxDevice.getDevice(), indexBuffer.buffer, "quad indices");
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),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
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 (...) {
cleanup(gfxDevice);
@@ -84,6 +87,9 @@ void SkinningPipeline::doSkinning(VkCommandBuffer cmd,
assert(mesh.hasSkeleton);
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{
.jointMatricesBuffer = getCurrentFrameData(frameIndex).jointMatricesBuffer.buffer.address,
.jointMatricesStartIndex = static_cast<std::uint32_t>(dc.jointMatricesStartIndex),
+2
View File
@@ -130,6 +130,8 @@ ImageID RenderResources::createImage(
if (!debugName.empty()) {
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;
}
+58 -2
View File
@@ -44,6 +44,9 @@ void GameRenderer::init(GfxDevice& gfxDevice, RenderResources& _resources, glm::
lightCullingPipeline = std::make_unique<LightCullingPipeline>();
lightCullingPipeline->init(gfxDevice, _resources, drawImageSize);
shadowMapPipeline = std::make_unique<ShadowMapPipeline>();
shadowMapPipeline->init(gfxDevice, _resources);
lineRenderingPass = std::make_unique<LineRenderingPass>();
lineRenderingPass->init(gfxDevice, drawImageFormat);
@@ -66,6 +69,7 @@ void GameRenderer::beginDrawing(GfxDevice& gfxDevice)
meshDrawCommands.clear();
skinningPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex());
lightCullingPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex());
shadowLightDirection.reset();
QuadRenderingManager::GetInstance().ClearQuads();
}
@@ -97,9 +101,11 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{
ZoneScopedN("GameRenderer::draw");
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "GameRenderer::draw");
vkutil::ScopedCmdLabel frameLabel(cmd, "GameRenderer::draw", vkutil::labelColors::frame);
{
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Skinning");
vkutil::ScopedCmdLabel label(cmd, "Skinning", vkutil::labelColors::compute);
skinningPipeline->flushCurrentFrame(
cmd,
@@ -118,10 +124,17 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Lights Buffer Flush");
vkutil::ScopedCmdLabel label(cmd, "Lights Buffer Flush", vkutil::labelColors::transfer);
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
const auto gpuSceneData = GPUSceneData{
.view = sceneData.camera.GetViewMatrix(),
@@ -139,11 +152,15 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
.numLights = lightCullingPipeline->getNumLights(),
.tileCountX = lightCullingPipeline->getTileCount().x,
.debugLightHeatmap = renderLightHeatmap ? 1u : 0u,
.shadowMapId = static_cast<std::uint32_t>(shadowMapPipeline->getShadowMapId()),
.shadowNormalOffset = shadowMapPipeline->getNormalOffset(),
.padding = 0,
.lightViewProj = lightViewProj,
};
{
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Material Buffer Barrier");
vkutil::ScopedCmdLabel label(cmd, "Material Buffer Barrier", vkutil::labelColors::transfer);
vkutil::bufferHostWriteToShaderReadBarrier(
cmd,
@@ -155,6 +172,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Upload Scene Data");
vkutil::ScopedCmdLabel label(cmd, "Upload Scene Data", vkutil::labelColors::transfer);
sceneDataBuffer.uploadNewData(
cmd,
@@ -189,8 +207,22 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
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");
vkutil::ScopedCmdLabel label(cmd, "Depth Prepass", vkutil::labelColors::depth);
auto depthPrepassInfo = vkutil::createRenderingInfo({
.renderExtent = drawImage.getExtent2D(),
@@ -215,6 +247,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Light Culling");
vkutil::ScopedCmdLabel label(cmd, "Light Culling", vkutil::labelColors::compute);
vkutil::transitionImage(
cmd,
@@ -247,6 +280,8 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
renderInfo.renderingInfo.pColorAttachments = &renderInfo.colorAttachment;
renderInfo.renderingInfo.pDepthAttachment = &renderInfo.depthAttachment;
vkutil::cmdBeginLabel(cmd, "Forward Pass", vkutil::labelColors::opaque);
{
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "vkCmdBeginRendering");
@@ -255,6 +290,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "MeshPipeline::draw");
vkutil::ScopedCmdLabel label(cmd, "MeshPipeline::draw", vkutil::labelColors::opaque);
meshPipeline->draw(
cmd,
@@ -268,6 +304,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "SkyboxPipeline::draw");
vkutil::ScopedCmdLabel label(cmd, "SkyboxPipeline::draw", vkutil::labelColors::sky);
skyboxPipeline->draw(cmd, *resources, camera);
}
@@ -278,8 +315,11 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
vkCmdEndRendering(cmd);
}
vkutil::cmdEndLabel(cmd);
{
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "LineRenderingPass::draw");
vkutil::ScopedCmdLabel label(cmd, "LineRenderingPass::draw", vkutil::labelColors::debug);
lineRenderingPass->draw(
cmd,
@@ -291,6 +331,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "QuadRendererPass::draw");
vkutil::ScopedCmdLabel label(cmd, "QuadRendererPass::draw", vkutil::labelColors::ui);
quadRendererPass->draw(
cmd,
@@ -302,7 +343,6 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
static_cast<float>(drawImage.extent.height),
0.0f, -1.0f, 1.0f));
}
// vkutil::cmdEndLabel(cmd);
}
void GameRenderer::drawQuads(
@@ -335,6 +375,9 @@ void GameRenderer::cleanup(GfxDevice& gfxDevice)
if (lightCullingPipeline)
lightCullingPipeline->cleanup(gfxDevice);
if (shadowMapPipeline)
shadowMapPipeline->cleanup(device);
if (skyboxPipeline)
skyboxPipeline->cleanup(device);
@@ -358,6 +401,8 @@ void GameRenderer::cleanup(GfxDevice& gfxDevice)
lineRenderingPass.reset();
quadRendererPass.reset();
lightCullingPipeline.reset();
shadowMapPipeline.reset();
shadowLightDirection.reset();
pendingMaterialUploads.clear();
meshDrawCommands.clear();
sortedMeshDrawCommands.clear();
@@ -402,7 +447,18 @@ void GameRenderer::drawSkinnedMesh(MeshID id,
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
@@ -71,6 +71,8 @@ void CubeMap::RenderToCubemap(
}
gfxDevice.getImmediateExecuter().immediateSubmit([&](VkCommandBuffer cmd) {
vkutil::ScopedCmdLabel label(cmd, "HDRI To Cubemap", vkutil::labelColors::sky);
VkImageMemoryBarrier barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
@@ -108,6 +110,8 @@ void CubeMap::RenderToCubemap(
scissor.extent = {size, size};
for (std::uint32_t face = 0; face < 6; ++face) {
vkutil::cmdBeginLabelFormatted(cmd, vkutil::labelColors::draw, "Cubemap Face %u", face);
PC pc{};
pc.viewMtx = viewMatrices[face];
pc.projMtx = m_projection;
@@ -153,6 +157,8 @@ void CubeMap::RenderToCubemap(
vkCmdDraw(cmd, 36, 1, 0, 0);
vkCmdEndRendering(cmd);
vkutil::cmdEndLabel(cmd);
}
barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
@@ -199,6 +205,7 @@ void CubeMap::CreateCubeMap(
.mipMap = false,
.isCubemap = true
});
vkutil::addDebugLabel(gfxDevice.getDevice(), cubeMapImage.image, "skybox cubemap");
std::array<VkImageView, 6> faceViews{};
@@ -220,6 +227,9 @@ void CubeMap::CreateCubeMap(
&viewInfo,
nullptr,
&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);
@@ -305,6 +315,7 @@ void CubeMap::InitCubemapPipeline(
PipelineConfigInfo pipelineConfig{};
Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
pipelineConfig.name = "HDRI To Cubemap Pipeline";
pipelineConfig.vertexAttributeDescriptions = {};
pipelineConfig.vertexBindingDescriptions = {};
+20
View File
@@ -21,6 +21,22 @@ void Swapchain::initSync(VkDevice device) {
for (std::uint32_t i = 0; i < FRAMES_IN_FLIGHT; ++i) {
VK_CHECK(vkCreateFence(device, &fenceCreateInfo, nullptr, &frames[i].renderFence));
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));
}
nameSwapchainObjects(vkbDevice);
extent = m_swapchain.extent;
dirty = false;
}
@@ -187,6 +205,8 @@ void Swapchain::recreateSwapchain(
VK_CHECK(vkCreateSemaphore(vkbDevice, &sci, nullptr, &sem));
}
nameSwapchainObjects(vkbDevice);
extent = m_swapchain.extent;
dirty = false;
}
+101 -101
View File
@@ -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{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_IMAGE,
.objectHandle = (std::uint64_t)image,
.objectType = objectType,
.objectHandle = objectHandle,
.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) {
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);
addDebugLabel(device, VK_OBJECT_TYPE_SHADER_MODULE, reinterpret_cast<std::uint64_t>(shaderModule), label);
}
void vkutil::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);
addDebugLabel(device, VK_OBJECT_TYPE_PIPELINE, reinterpret_cast<std::uint64_t>(pipeline), label);
}
void vkutil::addDebugLabel(VkDevice device, VkPipelineLayout layout, const char* label) {
addDebugLabel(device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, reinterpret_cast<std::uint64_t>(layout), label);
}
void vkutil::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);
addDebugLabel(device, VK_OBJECT_TYPE_BUFFER, reinterpret_cast<std::uint64_t>(buffer), label);
}
void vkutil::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,
addDebugLabel(device, VK_OBJECT_TYPE_SAMPLER, reinterpret_cast<std::uint64_t>(sampler), label);
}
void vkutil::addDebugLabel(VkDevice device, VkDescriptorPool descriptorPool, const char* 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) {
@@ -319,76 +389,6 @@ VkShaderModule vkutil::loadShaderModule(const std::filesystem::path& path, VkDev
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) {
return vkutil::createRenderingInfo(params);
}
+110 -98
View File
@@ -153,65 +153,65 @@ void LightKeeper::customInit()
characterModelOptions.loadSkeleton = true;
characterModelOptions.loadAnimations = true;
// auto charModel = ModelDoc::LoadModel(
// AssetFS::GetInstance().GetFullPath("engine://cotw-capybara-male/source/capybara.fbx").generic_string(),
// characterModelOptions
// );
// ModelDocUtils::LogModelDocSummary(charModel, "capybara.fbx");
//
// const auto& charPrimitive = ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow(
// charModel,
// "engine://cotw-capybara-male/source/capybara.fbx"
// );
//
// const auto charMeshID = resources.meshes().addMesh(gfxDevice, charPrimitive.mesh);
//
// const auto charTexturePath = ModelDocUtils::PickTexturePath(
// charModel,
// charPrimitive,
// AssetFS::GetInstance().GetFullPath(
// "engine://cotw-capybara-male/textures/capybara_male_light_brown_dif.ddsc.DECA.RE.pngballs")
// );
//
// const auto charTextureID = resources.loadImageFromFile(gfxDevice, charTexturePath);
// // const auto charTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("engine://char.jpg"));
// const auto charMaterialID = resources.materials().addMaterial({
// .baseColor = ModelDocUtils::GetImportedBaseColor(
// charModel, charPrimitive),
// .diffuseTexture = charTextureID,
// .name = ModelDocUtils::GetImportedMaterialName(
// charModel, charPrimitive, "CharacterMaterial"),
// });
//
// const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
// charMeshComp->SetMeshID(charMeshID);
// charMeshComp->SetMaterialID(charMaterialID);
//
// const auto animator = CharObj->AddComponent<Animator>();
// animator->setSkeleton(std::move(charModel.skeleton));
//
// std::string firstAnimationName;
//
// for (auto& clip : charModel.animations)
// {
// spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
//
// if (firstAnimationName.empty())
// firstAnimationName = clip.name;
//
// animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
// }
//
// if (!firstAnimationName.empty())
// {
// spdlog::info("Playing animation: '{}'", firstAnimationName);
// animator->play(firstAnimationName);
// }
//
// animator->play("capybara_canter_fwd_01|capybara_canter_fwd_01|run");
//
// CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f, 0.f, 0.f));
// CharObj->GetTransform().SetWorldScale(0.01f, 0.01f, 0.01f);
auto charModel = ModelDoc::LoadModel(
AssetFS::GetInstance().GetFullPath("engine://cotw-capybara-male/source/capybara.fbx").generic_string(),
characterModelOptions
);
ModelDocUtils::LogModelDocSummary(charModel, "capybara.fbx");
const auto& charPrimitive = ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow(
charModel,
"engine://cotw-capybara-male/source/capybara.fbx"
);
const auto charMeshID = resources.meshes().addMesh(gfxDevice, charPrimitive.mesh);
const auto charTexturePath = ModelDocUtils::PickTexturePath(
charModel,
charPrimitive,
AssetFS::GetInstance().GetFullPath(
"engine://cotw-capybara-male/textures/capybara_male_light_brown_dif.ddsc.DECA.RE.pngballs")
);
const auto charTextureID = resources.loadImageFromFile(gfxDevice, charTexturePath);
// const auto charTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("engine://char.jpg"));
const auto charMaterialID = resources.materials().addMaterial({
.baseColor = ModelDocUtils::GetImportedBaseColor(
charModel, charPrimitive),
.diffuseTexture = charTextureID,
.name = ModelDocUtils::GetImportedMaterialName(
charModel, charPrimitive, "CharacterMaterial"),
});
const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
charMeshComp->SetMeshID(charMeshID);
charMeshComp->SetMaterialID(charMaterialID);
const auto animator = CharObj->AddComponent<Animator>();
animator->setSkeleton(std::move(charModel.skeleton));
std::string firstAnimationName;
for (auto& clip : charModel.animations)
{
spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
if (firstAnimationName.empty())
firstAnimationName = clip.name;
animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
}
if (!firstAnimationName.empty())
{
spdlog::info("Playing animation: '{}'", firstAnimationName);
animator->play(firstAnimationName);
}
animator->play("capybara_canter_fwd_01|capybara_canter_fwd_01|run");
CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f, 0.f, 0.f));
CharObj->GetTransform().SetWorldScale(0.01f, 0.01f, 0.01f);
// ModelDoc::LoadOptions options{};
// options.meshImportMode = ModelDoc::MeshImportMode::MergedPerNode;
@@ -450,46 +450,58 @@ void LightKeeper::customInit()
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
auto sunObj = scene.CreateGameObject("Sun");
auto* sun = sunObj->AddComponent<LightComponent>(LightType::Directional);
sun->SetColor(glm::vec3{1.0f, 0.95f, 0.85f});
sun->SetIntensity(1.0f);
sunObj->GetTransform().SetWorldRotation(glm::vec3{-50.0f, 30.0f, 0.0f});
// auto sunObj = scene.CreateGameObject("Sun");
// auto* sun = sunObj->AddComponent<LightComponent>(LightType::Directional);
// sun->SetColor(glm::vec3{1.0f, 0.95f, 0.85f});
// sun->SetIntensity(1.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;
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});
}
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);
// 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");
texID = resources.loadImageFromFile(gfxDevice, texPath);
+3
View File
@@ -457,6 +457,7 @@ namespace {
light->SetIntensity(4.0f);
light->SetRange(7.5f);
light->SetConeAngles(0.2f, 0.4f);
light->SetCastShadows(true);
const auto data = light->Serialize();
@@ -472,6 +473,8 @@ namespace {
"LightComponent must round-trip intensity and range");
check(loaded->GetInnerConeAngle() == 0.2f && loaded->GetOuterConeAngle() == 0.4f,
"LightComponent must round-trip its cone angles");
check(loaded->GetCastShadows(),
"LightComponent must round-trip its cast shadows flag");
loaded->SetConeAngles(0.5f, 0.1f);
check(loaded->GetOuterConeAngle() >= loaded->GetInnerConeAngle(),