Order Independent Transparency を自分で実装しようとしています。何もなく終わったようなものです... 下の図でわかるように、MSAA を使用した OIT は何らかの問題があります。サンプルのせいだと思います。各三角形のエッジには 4 つのサンプルがあるためです (三角形のエッジのみ)。
MSAA あり/なしのアルファブレンディングと 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);
}
私の考えは、リスト内にサンプル番号を書き込むことです。最後にエンドピクチャをレンダリングするときに、リストノードを比較し、それらが接近している場合は、サンプル番号を確認して平均色を計算したいと考えています。しかし、実際のサンプル番号を取得する方法がわかりません...
ところで:このバグを修正するためのより良いアイデアを持っている人はいますか?高速な計算である必要はありません。リアルタイムでレンダリングしません。