fix: 阴影光源位置计算反向 + lookAt 垂直光退化——影子可见

根因1(致命):光源位置写成 lightDir*30。lightDir 是光的传播方向
(指向场景),乘 30 后光源跑到场景下方——从地面下方向上打光,
地面永远是光线第一个交点,物体永远不可能遮挡地面,影子恒不存在。
修复:光源位置 = -lightDir * 30(逆传播方向退回)。

根因2:垂直光(direction≈(0,-1,0))时 lookAt 的 up=(0,1,0) 与视线
平行,叉积为零 → 矩阵 NaN → shadow map 全垃圾。修复:|dir.y|>0.99
时改用 (0,0,1) 作为 up。

场景:地面 quad(Model::CreatePlane 程序化构造,AssetManager 缓存)
+ 主光调平让影子落在相机视野内。已截图验证影子可见。
This commit is contained in:
2026-09-22 15:08:08 +08:00
parent d55f644b68
commit b86ca460de
6 changed files with 82 additions and 5 deletions
@@ -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, texture) 只创建一次
ModelHandle CreatePlane(f32 size, const std::string& texturePath);
AssetCache<Model>& Models() { return m_Models; }
// 后续扩展点:TextureHandle / MaterialHandle / ShaderHandle
+10
View File
@@ -32,6 +32,12 @@ namespace Engine
DescriptorManager& descriptorManager,
vk::DescriptorSetLayout textureLayout,
const std::string& path);
// 程序化构造:单 quad 平面(XZ 平面朝上),不经过 assimp
static Scope<Model> CreatePlane(Device& device, MemoryAllocator& allocator,
DescriptorManager& descriptorManager,
vk::DescriptorSetLayout textureLayout,
f32 size, const std::string& texturePath);
~Model();
Model(const Model&) = delete;
@@ -40,6 +46,10 @@ namespace Engine
const std::vector<Scope<Mesh>>& GetMeshes() const { return m_Meshes; }
private:
struct ProceduralTag {};
Model(ProceduralTag, Device& device, MemoryAllocator& allocator,
DescriptorManager& descriptorManager,
vk::DescriptorSetLayout textureLayout);
void LoadModel(const std::string& path);
void ProcessNode(aiNode* node, const aiScene* scene);
Scope<Mesh> ProcessMesh(aiMesh* mesh, const aiScene* scene);