feat: Shadow pass 接入 RenderGraph,支持 SRT 变换与程序化平面
阴影(本修正的核心根因):
- Shadow pass 光源正交写深度(2048 D32),Forward 采样比较;
写入与采样共用同一 lightSpace 矩阵,杜绝姿态/镜像不一致
- 修复:push constant range 64B→128B(原 Shadow pass 推 {lightVP,model}
超出 layout 声明范围 = UB,阴影中模型矩阵读到垃圾导致旋转错乱)
- 修复:ShadowFactor 缺少 NDC→UV 映射(*0.5+0.5),采样区域整体错位
- 修复:RG ShaderRead stage 位值直转(eFragment=0x10 在 PipelineStage2
是 TESSELLATION_CONTROL),改为逐位显式映射
- Camera perspective 深度重映射到 Vulkan [0,1](公式与 ortho 不同:
M22=M22*0.5-0.5, M32*=0.5);光源 ortho remap 用 M32=M32*0.5+0.5
引擎配套:
- TransformComponent 重构为 position/rotation/scale + Compose()
- Texture::CreateSolidColor / Model::CreatePlane 程序化资产
(两段式上传公共路径),AssetManager.CreatePlane 带缓存入口
- RG 新增 GetPhysicalView(h, slot):按帧槽位把 RG 资源绑进外部描述符
(阴影图 per-slot 物理镜像各自绑定)
验证:validation 0 error 0 warning,阴影随实体旋转正确
This commit is contained in:
@@ -153,6 +153,9 @@ namespace Engine {
|
||||
Model* GetModel(ModelHandle h) const { return m_Models.Get(h); }
|
||||
void UnloadModel(ModelHandle h) { m_Models.Unload(h); }
|
||||
|
||||
// 程序化平面(纯色贴图):size 为半边长。带缓存,同参数共享一份。
|
||||
ModelHandle CreatePlane(f32 halfSize, u8 r, u8 g, u8 b);
|
||||
|
||||
AssetCache<Model>& Models() { return m_Models; }
|
||||
|
||||
// 后续扩展点:TextureHandle / MaterialHandle / ShaderHandle
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <Engine/Assets/AssetHandle.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace Engine {
|
||||
@@ -33,10 +34,31 @@ namespace Engine::ECS {
|
||||
std::string name;
|
||||
};
|
||||
|
||||
// 世界变换。当前直接存世界矩阵(渲染热路径友好);
|
||||
// 需要 SRT 编辑时再加 LocalTransform 组件 + 层级同步系统。
|
||||
// 世界变换:可编辑的 SRT 分量 + 派生的世界矩阵。
|
||||
// 编辑分量后调用 Compose() 重算 world;渲染热路径只读 world。
|
||||
// 层级(父子变换)留给后续的层级同步系统。
|
||||
struct TransformComponent {
|
||||
glm::vec3 position{0.0f};
|
||||
glm::vec3 rotation{0.0f}; // 欧拉角(度),应用顺序 Y→X→Z
|
||||
glm::vec3 scale{1.0f};
|
||||
glm::mat4 world{1.0f};
|
||||
|
||||
TransformComponent& SetPosition(const glm::vec3& p) { position = p; return *this; }
|
||||
TransformComponent& SetRotation(const glm::vec3& r) { rotation = r; return *this; }
|
||||
TransformComponent& SetScale(const glm::vec3& s) { scale = s; return *this; }
|
||||
|
||||
// 分量 → world 矩阵(T * R * S)
|
||||
TransformComponent& Compose()
|
||||
{
|
||||
glm::mat4 t = glm::translate(glm::mat4(1.0f), position);
|
||||
glm::mat4 r =
|
||||
glm::rotate(glm::mat4(1.0f), glm::radians(rotation.y), glm::vec3(0, 1, 0)) *
|
||||
glm::rotate(glm::mat4(1.0f), glm::radians(rotation.x), glm::vec3(1, 0, 0)) *
|
||||
glm::rotate(glm::mat4(1.0f), glm::radians(rotation.z), glm::vec3(0, 0, 1));
|
||||
glm::mat4 s = glm::scale(glm::mat4(1.0f), scale);
|
||||
world = t * r * s;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// 网格渲染体:引用共享的 Model 资产。
|
||||
|
||||
@@ -188,6 +188,11 @@ namespace Engine::RG {
|
||||
// 每帧 acquire 后调用,把当帧 swapchain image 绑到导入资源
|
||||
void SetImportedImage(TextureHandle h, vk::Image image, vk::ImageView view);
|
||||
|
||||
// 指定帧槽位的物理镜像 view(Compile 后有效)。
|
||||
// 用途:把 RG 管理的资源绑定到外部描述符(如阴影图采样)。
|
||||
// 注意:物理镜像按槽位各一份,槽位变化/重编译后必须重新获取。
|
||||
vk::ImageView GetPhysicalView(TextureHandle h, u32 frameSlot) const;
|
||||
|
||||
// ---- Pass 声明 ----
|
||||
|
||||
class PassBuilder {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <Engine/Core/Types.h>
|
||||
#include <Engine/Renderer/Mesh.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -32,6 +33,15 @@ namespace Engine
|
||||
DescriptorManager& descriptorManager,
|
||||
vk::DescriptorSetLayout textureLayout,
|
||||
const std::string& path);
|
||||
|
||||
// 程序化模型:单位法线朝上的 XZ 平面(纯色贴图),用于地面等。
|
||||
// size 为半边长(平面总边长 = 2*size)。
|
||||
struct ProceduralTag {};
|
||||
static Scope<Model> CreatePlane(Device& device, MemoryAllocator& allocator,
|
||||
DescriptorManager& descriptorManager,
|
||||
vk::DescriptorSetLayout textureLayout,
|
||||
f32 halfSize, u8 r, u8 g, u8 b);
|
||||
|
||||
~Model();
|
||||
|
||||
Model(const Model&) = delete;
|
||||
@@ -40,6 +50,11 @@ namespace Engine
|
||||
const std::vector<Scope<Mesh>>& GetMeshes() const { return m_Meshes; }
|
||||
|
||||
private:
|
||||
Model(Device& device, MemoryAllocator& allocator,
|
||||
DescriptorManager& descriptorManager,
|
||||
vk::DescriptorSetLayout textureLayout,
|
||||
ProceduralTag, f32 halfSize, const std::array<u8, 3>& color);
|
||||
|
||||
void LoadModel(const std::string& path);
|
||||
void ProcessNode(aiNode* node, const aiScene* scene);
|
||||
Scope<Mesh> ProcessMesh(aiMesh* mesh, const aiScene* scene);
|
||||
@@ -60,5 +75,4 @@ namespace Engine
|
||||
};
|
||||
} // namespace Engine
|
||||
|
||||
|
||||
#endif //HELLOVULKAN_MODEL_H
|
||||
|
||||
@@ -56,6 +56,7 @@ namespace Engine {
|
||||
private:
|
||||
void BuildGraph(); // 声明 pass 结构 + 首次 Compile
|
||||
void HandleResize();
|
||||
void UpdateShadowDescriptors();
|
||||
|
||||
Window& m_Window;
|
||||
|
||||
@@ -71,20 +72,32 @@ namespace Engine {
|
||||
Scope<RG::RenderGraph> m_RenderGraph;
|
||||
|
||||
// ---- 管线装配(shader object 方案,无 vk::Pipeline)----
|
||||
// Forward layout:3 个 set(UBO/贴图/阴影图)+ 128B push(与 Shadow pass
|
||||
// 共用上限;forward 的 shader block 只有 64B,block ⊂ range 合法)
|
||||
vk::PipelineLayout m_PipelineLayout;
|
||||
vk::DescriptorSetLayout m_UBOSetLayout;
|
||||
vk::DescriptorSetLayout m_TextureSetLayout;
|
||||
std::vector<vk::DescriptorSet> m_UBODescriptorSets; // 每帧槽位一个
|
||||
vk::DescriptorSetLayout m_ShadowSetLayout;
|
||||
std::vector<vk::DescriptorSet> m_UBODescriptorSets; // 每帧槽位一个
|
||||
std::vector<vk::DescriptorSet> m_ShadowDescriptorSets; // 每帧槽位一个
|
||||
vk::Sampler m_ShadowSampler;
|
||||
vk::ShaderEXT m_VertShader{};
|
||||
vk::ShaderEXT m_FragShader{};
|
||||
|
||||
// Shadow pass 独立装配:无 set,push constant = {lightVP, model} 128B
|
||||
vk::PipelineLayout m_ShadowPipelineLayout;
|
||||
vk::ShaderEXT m_ShadowVertShader{};
|
||||
vk::ShaderEXT m_ShadowFragShader{};
|
||||
|
||||
// ---- RenderGraph 资源句柄 ----
|
||||
RG::TextureHandle m_Backbuffer{};
|
||||
RG::TextureHandle m_Depth{};
|
||||
RG::TextureHandle m_ShadowMap{};
|
||||
|
||||
// ---- 当帧绑定(Render() 期间有效,供 pass 回调读取)----
|
||||
ECS::Scene* m_BoundScene = nullptr;
|
||||
Assets::AssetManager* m_BoundAssets = nullptr;
|
||||
glm::mat4 m_LightSpace{1.0f}; // 阴影光源 VP(每帧由 Render 算好)
|
||||
|
||||
vk::Extent2D m_Extent{};
|
||||
u32 m_CurrentFrame = 0;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#include "MemoryAllocator.h"
|
||||
@@ -20,7 +21,14 @@ namespace Engine {
|
||||
|
||||
class Texture {
|
||||
public:
|
||||
// 从磁盘图片加载
|
||||
Texture(Device& device, MemoryAllocator& allocator, const std::string& path);
|
||||
|
||||
// 程序化纹理:纯色(1x1),用于地面/调试等不依赖磁盘资产的场景
|
||||
struct ProceduralTag {};
|
||||
static Scope<Texture> CreateSolidColor(Device& device, MemoryAllocator& allocator,
|
||||
u8 r, u8 g, u8 b);
|
||||
|
||||
~Texture();
|
||||
|
||||
Texture(const Texture&) = delete;
|
||||
@@ -34,6 +42,13 @@ namespace Engine {
|
||||
vk::Sampler GetSampler() const { return m_Sampler; }
|
||||
|
||||
private:
|
||||
// 两段式构造:先确定像素来源(磁盘 / 程序化),再走公共上传路径
|
||||
Texture(Device& device, MemoryAllocator& allocator, ProceduralTag,
|
||||
const std::array<u8, 4>& rgba);
|
||||
|
||||
// 公共路径:staging → device local image → view/sampler
|
||||
void InitFromPixels(const void* pixels, u32 width, u32 height);
|
||||
|
||||
Device& m_Device;
|
||||
vk::Image m_Image;
|
||||
vk::ImageView m_View;
|
||||
|
||||
Reference in New Issue
Block a user