0

我尝试自己实施与订单无关的透明度。就像没有一件事就完成了......如下图所示,带有MSAA的OIT有点不对劲。我认为这是因为样品。因为在每个三角形边缘有 4 个样本(并且仅在三角形边缘)。

使用和不使用 MSAA 的 Alphablending 和 OIT

使用和不使用 MSAA 的 Alphablending 和 OIT

这里还有 HLSL 中的着色器代码:

创建列表

RWByteAddressBuffer tRWFragmentList : register(u1);

void main(PS_INPUT input)
{
    float2 position = (input.Pos.xy - float2(0.5,0.5)) / input.Pos.w;

    uint nXPosition = position.x;
    uint nYPosition = position.y;

    uint vScreenAddress = nScreenWidth * nYPosition + nXPosition;

    float3 Normal = normalize((float3)input.Normal);
    float3 Position = (float3)input.Pos;

    float4 Color = createphong(input);
    //float4 Color = (float4)input.Diffuse;

    // Get counter value and increment
    uint nNewFragmentAddress = 0;
    tRWFragmentList.InterlockedAdd(0, 44, nNewFragmentAddress);

    if (nNewFragmentAddress < 1000*1000*500)
    {
        uint pixel = 4 + nScreenWidth * nScreenHeight * 4 + nNewFragmentAddress;

        tRWFragmentList.Store(pixel + 4, asuint(Position.x));
        tRWFragmentList.Store(pixel + 8, asuint(Position.y));
        tRWFragmentList.Store(pixel + 12, asuint(Position.z));
        tRWFragmentList.Store(pixel + 16, asuint(Normal.x));
        tRWFragmentList.Store(pixel + 20, asuint(Normal.y));
        tRWFragmentList.Store(pixel + 24, asuint(Normal.z));
        tRWFragmentList.Store(pixel + 28, asuint(Color.r));
        tRWFragmentList.Store(pixel + 32, asuint(Color.g));
        tRWFragmentList.Store(pixel + 36, asuint(Color.b));
        tRWFragmentList.Store(pixel + 40, asuint(Color.a));

        uint output = 0;
        tRWFragmentList.InterlockedExchange(vScreenAddress * 4 + 4, pixel, output);
        tRWFragmentList.Store(pixel, output);
    }
}

对列表进行排序

RWByteAddressBuffer tRWFragmentList : register(u1);

float4 main(PS_INPUT input) : SV_Target
{
    float2 position = (input.Pos.xy - float2(0.5,0.5)) / input.Pos.w;

    uint nXPosition = position.x;
    uint nYPosition = position.y;

    uint vScreenAddress = 4+(nScreenWidth * nYPosition + nXPosition) * 4;

    if (tRWFragmentList.Load(vScreenAddress) != 0)
    {
        uint i = vScreenAddress;
        uint j = vScreenAddress;
        float zMin = 0;
        uint zMinPrev = i;

        do
        {
            i = j;
            zMin = asfloat(tRWFragmentList.Load(tRWFragmentList.Load(i) + 12));
            zMinPrev = i;
            do
            {
                if (asfloat(tRWFragmentList.Load(tRWFragmentList.Load(i) + 12)) > zMin)
                {
                    zMin = asfloat(tRWFragmentList.Load(tRWFragmentList.Load(i) + 12));
                    zMinPrev = i;
                }
                i = tRWFragmentList.Load(i);
            }
            while (tRWFragmentList.Load(i) > 0);

            //check swap
            if (zMinPrev != j)
            {
                uint trwJ = tRWFragmentList.Load(j);
                uint trwtrwMin = tRWFragmentList.Load(tRWFragmentList.Load(zMinPrev));
                uint trwMin = tRWFragmentList.Load(zMinPrev);
                tRWFragmentList.Store(j,trwMin);
                tRWFragmentList.Store(zMinPrev,trwtrwMin);
                tRWFragmentList.Store(trwMin,trwJ);
            }

            j = tRWFragmentList.Load(j);
        }
        while (tRWFragmentList.Load(j) > 0);
    }
    return float4(1, 0, 1, 1);
}

渲染完成的图片

RWByteAddressBuffer tRWFragmentList  : register(u1);

float4 main(PS_INPUT input) : SV_Target
{
    float2 position = (input.Pos.xy - float2(0.5,0.5)) / input.Pos.w;

    uint nXPosition = position.x;
    uint nYPosition = position.y;

    uint vScreenAddress = nScreenWidth * nYPosition + nXPosition;

    float3 Color = float3(0.5, 0.5, 0.5);
    uint nScreenAdress = vScreenAddress*4+4;

    while (tRWFragmentList.Load(nScreenAdress) != 0)
    {
        nScreenAdress = tRWFragmentList.Load(nScreenAdress);

        float4 NewColor = float4(asfloat(tRWFragmentList.Load(nScreenAdress + 28)),
                                 asfloat(tRWFragmentList.Load(nScreenAdress + 32)),
                                 asfloat(tRWFragmentList.Load(nScreenAdress + 36)),
                                 asfloat(tRWFragmentList.Load(nScreenAdress + 40)));

        float fZValue = asfloat(tRWFragmentList.Load(nScreenAdress + 12));
        Color = NewColor.a * NewColor.rgb + (1 - NewColor.a) * Color.rgb;               
    }
    tRWFragmentList.Store(vScreenAddress * 4 + 4, 0);
    if (nXPosition == 0 && nYPosition)
    {
        tRWFragmentList.Store(0, 0);
    }
    return float4(Color.r, Color.g, Color.b, 1);
}

我的想法是在列表中写入样本编号,最后在渲染 endpicture 时,我比较列表节点,如果它们要靠近,我想检查样本编号并计算平均颜色。但我不知道如何获得实际样本数......

顺便说一句:有人有更好的想法来修复这个错误吗?它不需要快速计算,我不会实时渲染。

4

1 回答 1

1

您必须使用sv_coverage在触摸片段的像素着色器中读取掩码。

有了它,您可以根据覆盖范围累积 N 个值( N 为 MSAA Nx ),然后平均和输出,从而解决透明度(和 msaa 一次)。

如果您想在解析之前在 msaa 表面中输出,则必须使用计算着色器才能进行一次累积,然后分别写入 N 个值。

除了实际的网格渲染,我会去计算所有东西,对于这种处理,它比像素着色器更方便

于 2016-07-28T15:53:22.853 回答