Получить номер образца MSAA внутри пиксельного шейдера для OIT
Я пытаюсь реализовать независимую прозрачность заказов самостоятельно. Это как закончено без единой вещи... Как вы можете видеть на картинке ниже, OIT с MSAA является своего рода неправильным. Я думаю, что это из-за образцов. потому что на каждом ребре треугольника есть 4 образца (и только на краях треугольника).
Alphablending и OIT с и без MSAA
вот также код шейдера в 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);
}
Моя идея состоит в том, чтобы записать номер образца в список, и в конце, когда я отображаю конечную картинку, я сравниваю узлы списка, и если они должны быть рядом, я хочу проверить номер образца и вычислить средний цвет. Но я не знаю, как получить актуальный номер образца...
Кстати: у кого-нибудь есть лучший идеал, чтобы исправить эту ошибку? Это не должен быть быстрый расчет, я не рендеринг в режиме реального времени.
1 ответ
Вы должны использовать sv_coverage
прочитать маску в пиксельном шейдере затронутых фрагментов.
С его помощью вы разрешаете прозрачность (и msaa за один раз) путем накопления в N значений ( N как MSAA Nx) в соответствии с покрытием, затем усреднением и выводом.
Если вы хотите вывести на поверхность msaa вместо разрешения, вам нужно использовать вычислительный шейдер, чтобы иметь возможность выполнить накопление, а затем записать N значений отдельно.
Я бы пошел вычислить для всего, кроме фактического рендеринга сетки, это более удобно, чем пиксельный шейдер для такого рода обработки