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

ReSTIR算法实现存在严重重影问题,求技术排查方案

ReSTIR时间滤波重影问题排查求助

近期实现了ReSTIR直接光照算法(基于概率计算直接光照),源码中所有ReSTIR相关代码位于Source\Samples\Restir目录。

问题现象

  • 开启时间滤波后出现重影(投影错误),相机前进时重影现象明显;关闭时间滤波后重影消失,但同时失去收敛效果
  • 开启降噪时重影更显著,但关闭降噪、提高相机移动速度时仍能清晰观察到重影,说明问题根源在时间滤波阶段
  • 特殊现象:相机后退时不会出现重影

已尝试的修复

曾修复OptixDenoiserPass中视图投影矩阵的转置问题,但修复后重影问题仍未解决

时间滤波着色器代码(Source\Samples\Restir\TemporalFilteringPass.slang)

#include "Light.slangh"
#include "Reservoir.slangh"

import Utils.Sampling.TinyUniformSampleGenerator;

cbuffer PerFrameCB
{
    uint2 viewportDims;
    float3 cameraPositionWs;
    float4x4 previousFrameViewProjMat;
    uint nbReservoirPerPixel;
    uint sampleIndex;
    uint motion;
    float temporalLinearDepthThreshold;
    float temporalWsRadiusThreshold;
    float temporalNormalThreshold;
};

RWStructuredBuffer<RestirReservoir> gCurrentFrameReservoirs;
StructuredBuffer<RestirReservoir> gPreviousFrameReservoirs;

Texture2D<float4> gCurrentPositionWs;
Texture2D<float4> gPreviousPositionWs;

Texture2D<float4> gCurrentNormalWs;
Texture2D<float4> gPreviousNormalWs;

Texture2D<float4> gAlbedo;
Texture2D<float4> gSpecular;

int2 getPreviousFramePixelPos(float4 P, float width, float height)
{
    float4 ndc = mul(P, previousFrameViewProjMat);
    ndc = ndc / ndc.w;
    float2 s = (ndc.xy + float2(1, 1)) * 0.5f;
    s = float2(s.x, 1.f - s.y);
    return (int2)(s * float2(width, height));
}

[numthreads(16, 16, 1)] void TemporalFilteringPass(uint3 threadId
                                                   : SV_DispatchThreadID)
{
    const uint2 pixel = threadId.xy;
    if (any(pixel >= viewportDims))
        return;

    if (gCurrentPositionWs[pixel].w == 0.0f)
        return;

    const float3 currP = gCurrentPositionWs[pixel].xyz;

    int2 previousPixelPos = getPreviousFramePixelPos(float4(currP, 1.0f), (float)viewportDims.x, (float)viewportDims.y);
    if (previousPixelPos.x < 0 || previousPixelPos.x >= (int)viewportDims.x)
        return;
    if (previousPixelPos.y < 0 || previousPixelPos.y >= (int)viewportDims.y)
        return;
    if (gPreviousPositionWs[previousPixelPos].w == 0.0f)
        return;

    const float3 prevP = gPreviousPositionWs[previousPixelPos].xyz;
    if (length(prevP - currP) > temporalWsRadiusThreshold)
        return;

    const float3 currN = gCurrentNormalWs[pixel].xyz;
    const float3 prevN = gPreviousNormalWs[previousPixelPos].xyz;

    if (length(prevN - currN) > temporalNormalThreshold)
        return;

    const float currlinearDepth = gCurrentNormalWs[pixel].w;
    const float prevlinearDepth = gPreviousNormalWs[pixel].w;

    if (abs(currlinearDepth - prevlinearDepth) > temporalLinearDepthThreshold)
        return;

    const float3 V = normalize(cameraPositionWs - currP);
    const float3 diffuse = gAlbedo[pixel].xyz;
    const float3 specular = gSpecular[pixel].xyz;
    const float roughness = gSpecular[pixel].w;

    // Current pixel
    const uint currentPixelLinearIndex = pixel.y * viewportDims.x + pixel.x;
    const uint currentPixelReservoirsStart = currentPixelLinearIndex * nbReservoirPerPixel;

    // Previous pixel
    const uint previousPixelLinearIndex = previousPixelPos.y * viewportDims.x + previousPixelPos.x;
    const uint previousPixelReservoirsStart = previousPixelLinearIndex * nbReservoirPerPixel;

    // Init rng
    TinyUniformSampleGenerator rng = TinyUniformSampleGenerator(pixel.xy, sampleIndex);

    // Combine reservoirs
    for (uint i = 0; i < nbReservoirPerPixel; ++i)
    {
        RestirReservoir currentReservoir = gCurrentFrameReservoirs[currentPixelReservoirsStart + i];

        RestirReservoir previousReservoir = gPreviousFrameReservoirs[previousPixelReservoirsStart + i];
        if (motion > 0)
        {
            // Clamp M according to paper. But use a smaller value(5) since it gives better results.
            previousReservoir.mM = min(5 * currentReservoir.mM, previousReservoir.mM);
        }

        gCurrentFrameReservoirs[currentPixelReservoirsStart + i] =
            combineReservoirs(currentReservoir, previousReservoir, currP, currN, V, diffuse, specular, roughness, rng);
    }
}

现寻求技术帮助,排查该重影问题的原因及解决办法。


内容的提问来源于stack exchange,提问作者TheChamp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 17:24:54