From ca3490e728bbd754a846d433aee5488fb130cd9c Mon Sep 17 00:00:00 2001 From: Lveyou <1339484752@qq.com> Date: Tue, 12 May 2026 19:48:32 +0800 Subject: [PATCH] =?UTF-8?q?*=20=E7=BA=A7=E8=81=94=E9=98=B4=E5=BD=B1?= =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dl/base/dl_type_user.h | 19 ++++ dl/dl_type.h | 1 + dl/render/dl_factory.cpp | 80 +++++++++++++++- dl/render/dl_factory.h | 5 +- dl/vk/dl_vertex.h | 2 +- dl/vk/dl_vk.cpp | 162 ++++++++++++++++++++++++-------- dl/vk/dl_vk.h | 18 ++-- project/dl_test/ui_actor.h | 32 +------ res/dl/shader/3d_bone_frag.spv | Bin 26552 -> 32924 bytes res/dl/shader/3d_bone_vert.spv | Bin 6976 -> 7120 bytes res/dl/shader/3d_frag.spv | Bin 26552 -> 32924 bytes res/dl/shader/3d_vert.spv | Bin 3332 -> 3492 bytes shader/3d.frag | 165 ++++++++++++++++++++++++++------- shader/3d.vert | 9 +- 14 files changed, 367 insertions(+), 126 deletions(-) diff --git a/dl/base/dl_type_user.h b/dl/base/dl_type_user.h index 80ae1a98..67fd9a34 100644 --- a/dl/base/dl_type_user.h +++ b/dl/base/dl_type_user.h @@ -51,6 +51,25 @@ struct RenderInfo3D {} }; +//! 调试绘图3d +enum class DebugView3D +{ + NONE, + DIFFUSE = 1, // 漫反射 + NORMAL, // 法线 + AO, // 几何遮蔽 + EMISSIVE, // 自发光 + METALLIC, // 金属度 + ROUGHNESS, // 粗糙度 + PBR_DIFFUSE = 10, // pbr漫反射 + PBR_F, // pbr 菲涅尔 + PBR_G, // pbr 几何遮蔽 + PBR_D, // pbr 微表面分布 + PBR_SPEC, // pbr 高光 + REFLECTION, // 反射向量 + CASCADE = 20, // 级联阴影 +}; + //! 设备属性 struct DeviceInfo { diff --git a/dl/dl_type.h b/dl/dl_type.h index 8252d8e1..59760bd6 100644 --- a/dl/dl_type.h +++ b/dl/dl_type.h @@ -16,3 +16,4 @@ #include "base/dl_type_create.h" #include "base/dl_type_convert.h" #include "base/dl_string_n.h" +#include "base/dl_type_user.h" diff --git a/dl/render/dl_factory.cpp b/dl/render/dl_factory.cpp index 2bd62cf9..e1f7e4cc 100644 --- a/dl/render/dl_factory.cpp +++ b/dl/render/dl_factory.cpp @@ -181,14 +181,86 @@ Camera* Factory::GetCamera() } -void Factory::SetDebugViewTexture(int texture) +void Factory::SetDebugView3D(DebugView3D type) { - g_vk->SetDebugViewTexture(texture); + g_vk->SetDebugView(type); } -void Factory::SetDebugViewPbr(int pbr) +void Factory::UpdateDebugView() { - g_vk->SetDebugViewPbr(pbr); + // + bool ctrl = g_input->KeyState(KeyCode::LEFT_CONTROL); + bool alt = g_input->KeyState(KeyCode::LEFT_ALT); + + if (!ctrl && !alt) + { + if (g_input->KeyDown(KeyCode::KP_0)) + SetDebugView3D((DebugView3D)0); + else if (g_input->KeyDown(KeyCode::KP_1)) + SetDebugView3D((DebugView3D)1); + else if (g_input->KeyDown(KeyCode::KP_2)) + SetDebugView3D((DebugView3D)2); + else if (g_input->KeyDown(KeyCode::KP_3)) + SetDebugView3D((DebugView3D)3); + else if (g_input->KeyDown(KeyCode::KP_4)) + SetDebugView3D((DebugView3D)4); + else if (g_input->KeyDown(KeyCode::KP_5)) + SetDebugView3D((DebugView3D)5); + else if (g_input->KeyDown(KeyCode::KP_6)) + SetDebugView3D((DebugView3D)6); + else if (g_input->KeyDown(KeyCode::KP_7)) + SetDebugView3D((DebugView3D)7); + else if (g_input->KeyDown(KeyCode::KP_8)) + SetDebugView3D((DebugView3D)8); + else if (g_input->KeyDown(KeyCode::KP_9)) + SetDebugView3D((DebugView3D)9); + } + else if (ctrl) + { + if (g_input->KeyDown(KeyCode::KP_0)) + SetDebugView3D((DebugView3D)10); + else if (g_input->KeyDown(KeyCode::KP_1)) + SetDebugView3D((DebugView3D)11); + else if (g_input->KeyDown(KeyCode::KP_2)) + SetDebugView3D((DebugView3D)12); + else if (g_input->KeyDown(KeyCode::KP_3)) + SetDebugView3D((DebugView3D)13); + else if (g_input->KeyDown(KeyCode::KP_4)) + SetDebugView3D((DebugView3D)14); + else if (g_input->KeyDown(KeyCode::KP_5)) + SetDebugView3D((DebugView3D)15); + else if (g_input->KeyDown(KeyCode::KP_6)) + SetDebugView3D((DebugView3D)16); + else if (g_input->KeyDown(KeyCode::KP_7)) + SetDebugView3D((DebugView3D)17); + else if (g_input->KeyDown(KeyCode::KP_8)) + SetDebugView3D((DebugView3D)18); + else if (g_input->KeyDown(KeyCode::KP_9)) + SetDebugView3D((DebugView3D)19); + } + else if (alt) + { + if (g_input->KeyDown(KeyCode::KP_0)) + SetDebugView3D((DebugView3D)20); + else if (g_input->KeyDown(KeyCode::KP_1)) + SetDebugView3D((DebugView3D)21); + else if (g_input->KeyDown(KeyCode::KP_2)) + SetDebugView3D((DebugView3D)22); + else if (g_input->KeyDown(KeyCode::KP_3)) + SetDebugView3D((DebugView3D)23); + else if (g_input->KeyDown(KeyCode::KP_4)) + SetDebugView3D((DebugView3D)24); + else if (g_input->KeyDown(KeyCode::KP_5)) + SetDebugView3D((DebugView3D)25); + else if (g_input->KeyDown(KeyCode::KP_6)) + SetDebugView3D((DebugView3D)26); + else if (g_input->KeyDown(KeyCode::KP_7)) + SetDebugView3D((DebugView3D)27); + else if (g_input->KeyDown(KeyCode::KP_8)) + SetDebugView3D((DebugView3D)28); + else if (g_input->KeyDown(KeyCode::KP_9)) + SetDebugView3D((DebugView3D)29); + } } gcSprite Factory::CreateSpriteDefault(const Color& col /*= ColorDef::WHITE*/) diff --git a/dl/render/dl_factory.h b/dl/render/dl_factory.h index af222694..d222dad4 100644 --- a/dl/render/dl_factory.h +++ b/dl/render/dl_factory.h @@ -175,8 +175,9 @@ public: Camera* GetCamera(); //! 设置调试绘图(3d) - void SetDebugViewTexture(int texture); - void SetDebugViewPbr(int pbr); + void SetDebugView3D(DebugView3D type); + + void UpdateDebugView(); //-----------------------------Sprite------------------------------ /** * @brief 创建默认精灵 diff --git a/dl/vk/dl_vertex.h b/dl/vk/dl_vertex.h index 96af3e91..55dadba6 100644 --- a/dl/vk/dl_vertex.h +++ b/dl/vk/dl_vertex.h @@ -267,8 +267,8 @@ struct alignas(16) UbPass float _prefilteredCubeMipLevels; // 预过滤的立方体贴图级数 float _scaleIBLAmbient; // ibl环境光系数 std::array _sh; // 球谐函数系数(环境光漫反射) + Position4 _cascadeSplits; float _debugView; - float _debugPbr; std::array _light; }; diff --git a/dl/vk/dl_vk.cpp b/dl/vk/dl_vk.cpp index a4e447a1..b2405d88 100644 --- a/dl/vk/dl_vk.cpp +++ b/dl/vk/dl_vk.cpp @@ -14,6 +14,14 @@ namespace dl { VK* g_vk = nullptr; +constexpr uint32_t BINDING_INDEX_UBO = 0; +constexpr uint32_t BINDING_INDEX_MATERIAL = 1; +constexpr uint32_t BINDING_INDEX_PASS = 2; +constexpr uint32_t BINDING_INDEX_CASCADE = 3; +constexpr uint32_t BINDING_INDEX_IBL = 4; +constexpr uint32_t BINDING_INDEX_BRDF = 5; +constexpr uint32_t BINDING_INDEX_SHADOW = 6; + void VK::_init(GLFWwindow* window) { _curPushConstant = 0; @@ -856,7 +864,7 @@ void VK::_create_graphics_pipeline() return; } - //深度模板状态 + // 深度模板状态 VkPipelineDepthStencilStateCreateInfo depthStencil{}; depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depthStencil.depthTestEnable = VK_TRUE; @@ -869,7 +877,7 @@ void VK::_create_graphics_pipeline() depthStencil.front = {}; // Optional depthStencil.back = {}; // Optional - //图形管线 + // 图形管线 VkGraphicsPipelineCreateInfo pipelineInfo{}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipelineInfo.stageCount = 2; @@ -1379,7 +1387,7 @@ void VK::_create_descriptor_set_layout_shadow() std::array descriptorWrites{}; descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrites[0].dstSet = _shadow._descriptorSets[i]; - descriptorWrites[0].dstBinding = 0; + descriptorWrites[0].dstBinding = BINDING_INDEX_UBO; descriptorWrites[0].dstArrayElement = 0; descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptorWrites[0].descriptorCount = 1; @@ -2234,7 +2242,7 @@ void VK::CopyBufferToImageMulti( void VK::CreateImage(uint32_t w, uint32_t h, uint32_t mip_level, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, - VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) + VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory, uint32_t layers) { VkImageCreateInfo imageInfo{}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -2243,7 +2251,7 @@ void VK::CreateImage(uint32_t w, uint32_t h, uint32_t mip_level, VkSampleCountFl imageInfo.extent.height = h; imageInfo.extent.depth = 1; imageInfo.mipLevels = mip_level; - imageInfo.arrayLayers = 1; + imageInfo.arrayLayers = layers; imageInfo.format = format; imageInfo.tiling = tiling; imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -2274,6 +2282,7 @@ void VK::CreateImage(uint32_t w, uint32_t h, uint32_t mip_level, VkSampleCountFl vkBindImageMemory(_device, image, imageMemory, 0); } + size_t VK::CreateTextureReal(Image* image, bool srgb, bool delete_image) { assert(image); @@ -2518,43 +2527,57 @@ void VK::_create_descriptor_set_layout() { // ubo VkDescriptorSetLayoutBinding uboLayoutBinding{}; - uboLayoutBinding.binding = 0; + uboLayoutBinding.binding = BINDING_INDEX_UBO; uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; uboLayoutBinding.descriptorCount = 1; uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; uboLayoutBinding.pImmutableSamplers = nullptr; // Optional // ubo material VkDescriptorSetLayoutBinding uboLayoutBinding1{}; - uboLayoutBinding1.binding = 1; + uboLayoutBinding1.binding = BINDING_INDEX_MATERIAL; uboLayoutBinding1.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; uboLayoutBinding1.descriptorCount = 1; uboLayoutBinding1.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;//像素着色器可见 uboLayoutBinding1.pImmutableSamplers = nullptr; // Optional // ubo pass VkDescriptorSetLayoutBinding uboLayoutBinding2{}; - uboLayoutBinding2.binding = 2; + uboLayoutBinding2.binding = BINDING_INDEX_PASS; uboLayoutBinding2.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; uboLayoutBinding2.descriptorCount = 1; uboLayoutBinding2.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;//像素着色器可见 uboLayoutBinding2.pImmutableSamplers = nullptr; // Optional + // ubo cascade + VkDescriptorSetLayoutBinding uboLayoutBinding3{}; + uboLayoutBinding3.binding = BINDING_INDEX_CASCADE; + uboLayoutBinding3.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uboLayoutBinding3.descriptorCount = 1; + uboLayoutBinding3.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;//像素着色器可见 + uboLayoutBinding3.pImmutableSamplers = nullptr; // Optional // ibl贴图 - VkDescriptorSetLayoutBinding texLayoutBinding3{}; - texLayoutBinding3.binding = 3; - texLayoutBinding3.descriptorCount = 1; - texLayoutBinding3.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - texLayoutBinding3.pImmutableSamplers = nullptr; - texLayoutBinding3.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + VkDescriptorSetLayoutBinding texLayoutBinding{}; + texLayoutBinding.binding = BINDING_INDEX_IBL; + texLayoutBinding.descriptorCount = 1; + texLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + texLayoutBinding.pImmutableSamplers = nullptr; + texLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; // brdf贴图 - VkDescriptorSetLayoutBinding texLayoutBinding4{}; - texLayoutBinding4.binding = 4; - texLayoutBinding4.descriptorCount = 1; - texLayoutBinding4.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - texLayoutBinding4.pImmutableSamplers = nullptr; - texLayoutBinding4.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + VkDescriptorSetLayoutBinding texLayoutBinding1{}; + texLayoutBinding1.binding = BINDING_INDEX_BRDF; + texLayoutBinding1.descriptorCount = 1; + texLayoutBinding1.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + texLayoutBinding1.pImmutableSamplers = nullptr; + texLayoutBinding1.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + // 阴影贴图 + VkDescriptorSetLayoutBinding texLayoutBinding2{}; + texLayoutBinding2.binding = BINDING_INDEX_SHADOW; + texLayoutBinding2.descriptorCount = 1; + texLayoutBinding2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + texLayoutBinding2.pImmutableSamplers = nullptr; + texLayoutBinding2.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - std::array bindings = { - uboLayoutBinding, uboLayoutBinding1, uboLayoutBinding2, - texLayoutBinding3, texLayoutBinding4 + std::array bindings = { + uboLayoutBinding, uboLayoutBinding1, uboLayoutBinding2, uboLayoutBinding3, + texLayoutBinding, texLayoutBinding1, texLayoutBinding2 }; VkDescriptorSetLayoutCreateInfo layoutInfo{}; @@ -2745,7 +2768,6 @@ void VK::_create_uniform_buffers() _pass._scaleIBLAmbient = 1.0f; _pass._sh = {}; _pass._debugView = 0; - _pass._debugPbr = 0; } void VK::_create_uniform_bone() @@ -2879,7 +2901,7 @@ void VK::_create_ibl() std::array descriptorWrites{}; descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrites[0].dstSet = _descriptorSets[i]; - descriptorWrites[0].dstBinding = 4; + descriptorWrites[0].dstBinding = BINDING_INDEX_BRDF; descriptorWrites[0].dstArrayElement = 0; descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptorWrites[0].descriptorCount = 1; @@ -3611,7 +3633,7 @@ size_t VK::CreatePrimitive(ModelMaterial& m) std::array descriptorWrites{}; descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrites[0].dstSet = _descriptorSets[index]; - descriptorWrites[0].dstBinding = 0; + descriptorWrites[0].dstBinding = BINDING_INDEX_UBO; descriptorWrites[0].dstArrayElement = 0; descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptorWrites[0].descriptorCount = 1; @@ -3619,7 +3641,7 @@ size_t VK::CreatePrimitive(ModelMaterial& m) descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrites[1].dstSet = _descriptorSets[index]; - descriptorWrites[1].dstBinding = 1; + descriptorWrites[1].dstBinding = BINDING_INDEX_MATERIAL; descriptorWrites[1].dstArrayElement = 0; descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptorWrites[1].descriptorCount = 1; @@ -3627,7 +3649,7 @@ size_t VK::CreatePrimitive(ModelMaterial& m) descriptorWrites[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrites[2].dstSet = _descriptorSets[index]; - descriptorWrites[2].dstBinding = 2; + descriptorWrites[2].dstBinding = BINDING_INDEX_PASS; descriptorWrites[2].dstArrayElement = 0; descriptorWrites[2].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptorWrites[2].descriptorCount = 1; @@ -4773,28 +4795,90 @@ void VK::_create_shadow() _shadow._cascade.resize(NUM_SHADOW_CASCADE); + + Texture& tex = _shadow._tex; + CreateImage(SIZE_SHADOW_IMAGE, SIZE_SHADOW_IMAGE, 1, + VK_SAMPLE_COUNT_1_BIT, FORMAT_SHADOW_IMAGE, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, // 深度附件,着色器采样 + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, tex._image, tex._memory, NUM_SHADOW_CASCADE); + + // 整个View + { + VkImageViewCreateInfo viewInfo{}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = tex._image; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.format = FORMAT_SHADOW_IMAGE; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = NUM_SHADOW_CASCADE; + + if (vkCreateImageView(_device, &viewInfo, nullptr, &tex._imageView) != VK_SUCCESS) + { + log_err0("创建图像视图失败!"); + return; + } + } + for (size_t i = 0; i < NUM_SHADOW_CASCADE; ++i) { - Texture& tex = _shadow._cascade[i]._tex; - CreateImage(SIZE_SHADOW_IMAGE, SIZE_SHADOW_IMAGE, 1, - VK_SAMPLE_COUNT_1_BIT, FORMAT_SHADOW_IMAGE, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, // 深度附件,着色器采样 - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, tex._image, tex._memory); - - tex._imageView = CreateImageView(tex._image, FORMAT_SHADOW_IMAGE, VK_IMAGE_ASPECT_DEPTH_BIT, 1); + // 切片View + VkImageViewCreateInfo viewInfo{}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = tex._image; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.format = FORMAT_SHADOW_IMAGE; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = (uint32_t)i; + viewInfo.subresourceRange.layerCount = 1; + if (vkCreateImageView(_device, &viewInfo, nullptr, &_shadow._cascade[i]._imageView) != VK_SUCCESS) + { + log_err0("创建图像视图1失败!"); + return; + } + // 帧缓冲 VkFramebufferCreateInfo fbCI{}; fbCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; fbCI.renderPass = _shadow._renderPass; fbCI.attachmentCount = 1; // 只绑定一个深度附件 - fbCI.pAttachments = &tex._imageView; + fbCI.pAttachments = &_shadow._cascade[i]._imageView; fbCI.width = SIZE_SHADOW_IMAGE; fbCI.height = SIZE_SHADOW_IMAGE; fbCI.layers = 1; vkCreateFramebuffer(_device, &fbCI, nullptr, &_shadow._cascade[i]._frameBuffer); } + + // 更新描述符 + { + // shadow + VkDescriptorImageInfo imageInfo{}; + imageInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + imageInfo.imageView = _shadow._tex._imageView; + imageInfo.sampler = _skybox._brdfSampler;// todo + + for (size_t i = 0; i < _descriptorSets.size(); ++i) + { + std::array descriptorWrites{}; + descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[0].dstSet = _descriptorSets[i]; + descriptorWrites[0].dstBinding = BINDING_INDEX_SHADOW; + descriptorWrites[0].dstArrayElement = 0; + descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrites[0].descriptorCount = 1; + descriptorWrites[0].pImageInfo = &imageInfo; + + vkUpdateDescriptorSets(_device, + (uint32_t)descriptorWrites.size(), descriptorWrites.data(), + 0, nullptr); + } + } } void VK::_delete_shadow() @@ -4802,9 +4886,9 @@ void VK::_delete_shadow() for (auto& iter : _shadow._cascade) { vkDestroyFramebuffer(_device, iter._frameBuffer, nullptr); - iter._tex.Delete(_device); + vkDestroyImageView(_device, iter._imageView, nullptr); } - + _shadow._tex.Delete(_device); for (auto& iter : _shadow._ubCsmBuffer) vkDestroyBuffer(_device, iter, nullptr); for (auto& iter : _shadow._ubCsmMemory) @@ -5190,7 +5274,7 @@ void VK::LoadSkybox(std::string_view path) std::array descriptorWrites{}; descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrites[0].dstSet = _descriptorSets[i]; - descriptorWrites[0].dstBinding = 3; + descriptorWrites[0].dstBinding = BINDING_INDEX_IBL; descriptorWrites[0].dstArrayElement = 0; descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptorWrites[0].descriptorCount = 1; diff --git a/dl/vk/dl_vk.h b/dl/vk/dl_vk.h index 8b1777c1..d50aa6b4 100644 --- a/dl/vk/dl_vk.h +++ b/dl/vk/dl_vk.h @@ -610,7 +610,7 @@ public: */ void CreateImage(uint32_t w, uint32_t h, uint32_t mip_level, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, - VkImage& image, VkDeviceMemory& imageMemory); + VkImage& image, VkDeviceMemory& imageMemory, uint32_t layers = 1); /** * @brief 创建图像视图 @@ -745,15 +745,10 @@ public: _mapBoneUse[id] = true; } - void SetDebugViewTexture(int texture) + void SetDebugView(DebugView3D type) { - _pass._debugView = (float)texture; + _pass._debugView = (float)type; } - void SetDebugViewPbr(int pbr) - { - _pass._debugPbr = (float)pbr; - } - //! 真正的创建一个纹理,失败返回0 size_t CreateTextureReal(Image* image, bool srgb, bool delete_image); @@ -878,7 +873,7 @@ private: std::vector _uniformBuffers; //统一缓冲 std::vector _uniformBuffersMemory; //统一缓冲内存 VkDescriptorPool _descriptorPool; //描述符池 - std::vector _descriptorSets; // 描述符集(ubo、matrial、pass、ibl) + std::vector _descriptorSets; // 描述符集(ubo、matrial、pass、cascade、ibl、brdf) std::vector _descriptorSetsTex; // 描述符集(纹理) std::vector _descriptorSetsBone; // 描述符集(带骨骼动画) VkSampler _standardSampler; // 纹理采样器(标准) @@ -950,11 +945,12 @@ private: Pipeline _pipelineBone; std::vector _ubCsmBuffer; std::vector _ubCsmMemory; - UbCSM _ubCsm; + UbCSM _ubCsm; + Texture _tex; struct Cascade { - Texture _tex; + VkImageView _imageView; VkFramebuffer _frameBuffer; }; std::vector _cascade; diff --git a/project/dl_test/ui_actor.h b/project/dl_test/ui_actor.h index f950de2d..b75d47d8 100644 --- a/project/dl_test/ui_actor.h +++ b/project/dl_test/ui_actor.h @@ -61,37 +61,7 @@ public: else g_system->SetCursorMode(System::CursorMode::NORMAL); - // - if (g_input->KeyDown(KeyCode::F1)) - g_factory->SetDebugViewTexture(0); - else if (g_input->KeyDown(KeyCode::F2)) - g_factory->SetDebugViewTexture(1); - else if (g_input->KeyDown(KeyCode::F3)) - g_factory->SetDebugViewTexture(2); - else if (g_input->KeyDown(KeyCode::F4)) - g_factory->SetDebugViewTexture(3); - else if (g_input->KeyDown(KeyCode::F5)) - g_factory->SetDebugViewTexture(4); - else if (g_input->KeyDown(KeyCode::F6)) - g_factory->SetDebugViewTexture(5); - else if (g_input->KeyDown(KeyCode::F7)) - g_factory->SetDebugViewTexture(6); - - - if (g_input->KeyDown(KeyCode::KP_0)) - g_factory->SetDebugViewPbr(0); - else if (g_input->KeyDown(KeyCode::KP_1)) - g_factory->SetDebugViewPbr(1); - else if (g_input->KeyDown(KeyCode::KP_2)) - g_factory->SetDebugViewPbr(2); - else if (g_input->KeyDown(KeyCode::KP_3)) - g_factory->SetDebugViewPbr(3); - else if (g_input->KeyDown(KeyCode::KP_4)) - g_factory->SetDebugViewPbr(4); - else if (g_input->KeyDown(KeyCode::KP_5)) - g_factory->SetDebugViewPbr(5); - else if (g_input->KeyDown(KeyCode::KP_6)) - g_factory->SetDebugViewPbr(6); + g_factory->UpdateDebugView(); Value v = _lst->GetSelectClickDouble(); if (v) diff --git a/res/dl/shader/3d_bone_frag.spv b/res/dl/shader/3d_bone_frag.spv index 98333bcaaa4f68858f698d7758abd59355998ca2..d4f7ad34146048a942823c4341b9a7c3d928f06f 100644 GIT binary patch literal 32924 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 RpRrFx*GJy-Qr+|N{{a_TBz^z@ diff --git a/res/dl/shader/3d_bone_vert.spv b/res/dl/shader/3d_bone_vert.spv index 560c20428853f0e63898517476b858dd1842aabb..bc54b61ce3c6e17ebe803a27aa5733943c3708e5 100644 GIT binary patch delta 2154 zcmYk7%WqXx6o>bHw%l?fTAB-~5DOEH8g)>Vm>LN&Fu_-(4$ajXb4}?XrNG4GjvSac zxt=iek02eAs53FJC^QkR?6Fl zLMVksXoitqbF#Ftw|nBYuR;iyz!mTV_zCvFbe=u>XmSXBD6FLI%J|p{tn1)>^1OQ;+e+H2jCQq@ z!87dx9>G!#ausl}J%e8*e1?4Z=>)kJ%sM%|fNy7^lgwqDRlpTlm|Hcg3U2@O-MMas zow-cS>{g5Y@%_{H%U}=vHi9$RLmu{i8*oK^B3Cord2Aif zorSu$>F?`OkMW$tfW4bNI|-BUfO8l;;2hMeh20sbTZ;b9Ks}ZpJ3j*FvV1ucl5>w- zIoyzwUY?QZ@!Dup_n2>E@mT#(`Np@PyzvFFl_~SA8?ElAg`*9-pIp>!n1^pipJe|W zc;_wXU$T2u1L&`A1LdM_1JzsDFSFNy@jU+>yEb|JyBT4JC3X0o-OCDxOt<55USI%U ze!NhB8?N2+R|}h^>aXqqV*Fo`_08?wYLIXuF~A?l>-r9Pg-*x-Hxuw*b}QNl?4zwV zn4C6YA_nw~b`w$eONog)$wvBWf?4(W(=(i#-59s=zTiiTycKz4`g!AZ| zU>DEib@sQ@iA|$-zM}*lgEjCeAm@4{3}*v;7g_#P+TPUKavDhwa_oD&hb(_O^H@UC z!(ql4XOQKW(%wz2?)yka^_-UVw8aN^78rLM(B}ynBL4x%tc@Ck|+Jp^vx^u+z0*x)sQRd delta 2025 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 RpRrFx*GJy-Qr+|N{{a_TBz^z@ diff --git a/res/dl/shader/3d_vert.spv b/res/dl/shader/3d_vert.spv index b8bb95cc4e5da10c7792b6e47efb3ab16e92536f..646bad0cafbeee6fe22e7f8ec2a67d1996d56690 100644 GIT binary patch literal 3492 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 -1.0 && shadowCoord.z < 1.0 ) + { + float dist = texture(shadowMap, vec3(shadowCoord.st + offset, cascadeIndex)).r; + if (shadowCoord.w > 0 && dist < shadowCoord.z - bias) + { + shadow = ambient; + } + } + return shadow; +} +// 百分比渐进过滤 +float filterPCF(vec4 sc, uint cascadeIndex) +{ + ivec2 texDim = textureSize(shadowMap, 0).xy; + float scale = 0.75; + float dx = scale * 1.0 / float(texDim.x); + float dy = scale * 1.0 / float(texDim.y); + + float shadowFactor = 0.0; + int count = 0; + int range = 1; + + for (int x = -range; x <= range; x++) + { + for (int y = -range; y <= range; y++) + { + shadowFactor += textureProj(sc, vec2(dx*x, dy*y), cascadeIndex); + count++; + } + } + return shadowFactor / count; +} + + void main() { float perceptualRoughness; @@ -340,6 +401,34 @@ void main() vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV); // 最终光照 = 漫反射 + 高光,受法线与灯光夹角影响 vec3 color = NdotL * u_LightColor * (diffuseContrib + specContrib); + + + //----------------------------------阴影计算 + // 返回所在级联 + uint cascadeIndex = 0; + for(uint i = 0; i < SHADOW_MAP_CASCADE_COUNT - 1; ++i) + { + if(inViewPos.z < pass.cascadeSplits[i]) + { + cascadeIndex = i + 1; + } + } + + // 所在贴图位置 + vec4 shadowCoord = (biasMat * cascade.viewProj[cascadeIndex]) * vec4(inPosition, 1.0); + + float shadow = 0; + if (enablePCF == 1) + { + shadow = filterPCF(shadowCoord / shadowCoord.w, cascadeIndex); + } + else + { + shadow = textureProj(shadowCoord / shadowCoord.w, vec2(0.0), cascadeIndex); + } + // 只影响直射光 + color *= shadow; + // 计算ibl光照 color += getIBLContribution(pbrInputs, n, reflection); @@ -385,42 +474,48 @@ void main() case 6: // 粗糙度 outColor.rgb = texture(physicalMap, inUV0).ggg; break; - } - outColor = SRGBtoLINEAR(outColor); - } - - // PBR 光照方程 调试可视化 - // 可选显示内容: - // "none" 关闭调试(显示最终颜色) - // "Diff (l,n)" 只显示漫反射项 - // "F (l,h)" 只显示菲涅尔项 - // "G (l,v,h)" 只显示几何遮蔽项 - // "D (h)" 只显示微表面分布项 - // "Specular" 只显示高光项 - // "reflection" 反射向量 - if (pass.debugViewEquation > 0.0) - { - int index = int(pass.debugViewEquation); - switch (index) - { - case 1: - outColor.rgb = diffuseContrib; + // PBR 光照方程 调试可视化 + case 10: + outColor.rgb = diffuseContrib; // 漫反射 break; - case 2: - outColor.rgb = F; + case 11: + outColor.rgb = F; // 菲涅尔 break; - case 3: - outColor.rgb = vec3(G); + case 12: + outColor.rgb = vec3(G); // 几何遮蔽 break; - case 4: - outColor.rgb = vec3(D); + case 13: + outColor.rgb = vec3(D); // 微表面分布 break; - case 5: - outColor.rgb = specContrib; + case 14: + outColor.rgb = specContrib; // 高光 break; - case 6:// 点 -> 光 - outColor.rgb = reflection; - break; - } + case 15:// 点 -> 光 + outColor.rgb = reflection; // 反射向量 + break; + // 级联阴影 + case 20: + { + switch(cascadeIndex) + { + case 0 : + outColor.rgb *= vec3(1.0f, 0.25f, 0.25f); + break; + case 1 : + outColor.rgb *= vec3(0.25f, 1.0f, 0.25f); + break; + case 2 : + outColor.rgb *= vec3(0.25f, 0.25f, 1.0f); + break; + case 3 : + outColor.rgb *= vec3(1.0f, 1.0f, 0.25f); + break; + } + } + break; + case 21: + outColor.rgb = vec3(shadow); // 阴影贴图 + break; + } } } diff --git a/shader/3d.vert b/shader/3d.vert index e947c914..bd1ef874 100644 --- a/shader/3d.vert +++ b/shader/3d.vert @@ -45,6 +45,7 @@ layout (location = 1) out vec3 outNormal; layout (location = 2) out vec2 outUV0; layout (location = 3) out vec2 outUV1; layout (location = 4) out vec4 outColor; +layout (location = 5) out vec3 outViewPos; void main() { @@ -70,15 +71,17 @@ void main() vec3 posL = inPosition; vec3 normalL = inNormal; #endif - vec3 worldPos = (constant.model * vec4(posL, 1.0)).xyz; + vec4 worldPos = constant.model * vec4(posL, 1.0); mat3 normalMat = transpose(inverse(mat3(constant.model))); vec3 worldNormal = normalize(normalMat * normalL); + vec4 viewPos = ubo.view * worldPos; // 相机空间位置 - outPosition = worldPos; + outPosition = worldPos.xyz; outNormal = worldNormal; outUV0 = inUV0; outUV1 = inUV1; outColor = inColor * constant.color; + outViewPos = viewPos.xyz; - gl_Position = ubo.proj * ubo.view * vec4(worldPos, 1.0); + gl_Position = ubo.proj * ubo.view * worldPos; }