You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DirectX11延迟渲染场景下粒子系统渲染顺序与层级问题咨询

延迟着色下粒子系统的渲染整合方案

核心问题分析

你遇到的粒子始终在场景上层的问题,本质是粒子渲染阶段没有参与场景的深度测试,且渲染顺序不符合延迟着色的管线逻辑——延迟着色输出的场景图像已经是最终颜色缓冲,直接在上面画粒子会跳过深度遮挡检测,自然会覆盖所有场景内容。


正确的渲染执行顺序

调整后的完整流程如下,分阶段处理不透明场景和粒子:

  1. GBuffer生成阶段

    • 渲染所有不透明场景物体,将法线、世界空间位置、漫反射、粗糙度等数据写入GBuffer,同时把这些物体的深度值写入主DepthStencilBuffer。
    • 注:如果你的粒子是不透明类型(比如固体碎片),需要和普通物体一起在这一步渲染,写入GBuffer和深度缓冲;但绝大多数粒子是半透明的,这一步无需处理。
  2. 延迟光照计算阶段

    • 利用GBuffer、主深度缓冲、光照信息完成场景光照计算,输出结果到一个HDR颜色缓冲(比如命名为SceneColorBuffer),这个缓冲保存了不透明场景的最终光照效果。
  3. 粒子模拟与渲染阶段

    • 先通过计算着色器完成粒子的物理模拟(更新位置、速度、生命周期等数据)。
    • 渲染粒子公告板:
      • 开启深度测试,使用主深度缓冲,设置测试模式为D3D11_COMPARISON_LESS_EQUAL,确保粒子会被场景中更近的物体遮挡。
      • 半透明粒子要关闭深度写入(DepthWriteMask_Zero),避免后续粒子被当前粒子错误遮挡;不透明粒子则保持深度写入。
      • 设置对应混合模式:比如常规半透明用SRC_ALPHA和INV_SRC_ALPHA,火焰类效果可以用ONE和ONE的加法混合。
      • 将粒子直接渲染到SceneColorBuffer上,实现和场景的正确叠加。

公告板四边形的位置校正要点

要让公告板正确显示在场景空间中,需注意以下细节:

  • 矩阵转换一致性:粒子顶点的转换必须和场景物体使用完全相同的视图、投影矩阵,确保从世界空间到裁剪空间的转换一致,避免位置偏移。
  • 面向相机的正确实现:几何着色器中,基于相机的方向向量生成公告板的四个顶点,示例HLSL代码如下:
    [maxvertexcount(4)]
    void GS(point ParticleInput input[1], inout TriangleStream<ParticleOutput> stream)
    {
        float3 particleWorldPos = input[0].worldPos;
        float3 cameraWorldPos = g_CameraPosition; // 全局相机世界位置
        
        // 计算公告板的朝向向量
        float3 lookDir = normalize(cameraWorldPos - particleWorldPos);
        float3 rightDir = normalize(cross(lookDir, float3(0.0f, 1.0f, 0.0f))); // 世界上向量,或相机上向量
        float3 upDir = normalize(cross(rightDir, lookDir));
        
        // 粒子半长
        float halfSize = input[0].size * 0.5f;
        
        // 生成四个顶点
        float3 v0 = particleWorldPos - rightDir * halfSize + upDir * halfSize;
        float3 v1 = particleWorldPos + rightDir * halfSize + upDir * halfSize;
        float3 v2 = particleWorldPos - rightDir * halfSize - upDir * halfSize;
        float3 v3 = particleWorldPos + rightDir * halfSize - upDir * halfSize;
        
        // 转换到裁剪空间并输出
        ParticleOutput output;
        output.pos = mul(float4(v0, 1.0f), g_ViewProjectionMatrix);
        stream.Append(output);
        
        output.pos = mul(float4(v1, 1.0f), g_ViewProjectionMatrix);
        stream.Append(output);
        
        output.pos = mul(float4(v2, 1.0f), g_ViewProjectionMatrix);
        stream.Append(output);
        
        output.pos = mul(float4(v3, 1.0f), g_ViewProjectionMatrix);
        stream.Append(output);
    }
    
  • 深度值正确性:不要手动修改粒子的深度值,让矩阵转换自动生成齐次空间的深度,确保和场景深度缓冲的计算逻辑一致,深度测试才能正常工作。

额外提示

  • 如果粒子需要接收光照:
    • 简单方案:在粒子像素着色器中直接计算(比如使用场景环境光,或传递单个点光源参数),适合轻量效果。
    • 复杂方案:仅针对不透明粒子,将其几何信息写入GBuffer,在延迟光照阶段统一计算光照,但半透明粒子不适用这种方式。
  • 测试时可以先关闭混合,开启深度写入和测试,观察粒子是否被场景物体遮挡,确认深度逻辑正确后再开启混合效果。

内容的提问来源于stack exchange,提问作者Charlie.Q

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 19:37:49